# app.py - Aplicación Flask completa con inicialización automática de BD
from flask import Flask, request, jsonify, render_template, redirect, url_for
from flask_cors import CORS
from flask_login import LoginManager, login_required, login_user, logout_user, current_user
from models import db, Cliente, Usuario
import os
from datetime import datetime, timedelta, date
from dotenv import load_dotenv

# Cargar variables de entorno
load_dotenv()

# Crear la aplicación Flask
app = Flask(__name__)

# CONFIGURACIÓN USANDO VARIABLES DE ENTORNO
DB_SERVER = os.getenv('DB_SERVER', 'localhost')
DB_PORT = os.getenv('DB_PORT', '1433')
DB_DATABASE = os.getenv('DB_DATABASE', 'GestionClientes')
DB_USERNAME = os.getenv('DB_USERNAME', 'sa')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'Sistemas123*/')
DB_DRIVER = os.getenv('DB_DRIVER', 'ODBC Driver 17 for SQL Server')

# Construir la cadena de conexión
app.config['SQLALCHEMY_DATABASE_URI'] = (
    f"mssql+pyodbc://{DB_USERNAME}:{DB_PASSWORD}@{DB_SERVER}:{DB_PORT}/{DB_DATABASE}"
    f"?driver={DB_DRIVER.replace(' ', '+')}&TrustServerCertificate=yes&Encrypt=yes"
)

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'K8m2#D9v$L4x@R7n*W5q&F1s!P6j%T3y^B8e@N7k$H4m*V9r&L2x#Q5w')
app.config['DEBUG'] = os.getenv('DEBUG', 'False').lower() in ['true', '1', 'yes']

# Configuraciones adicionales para Flask-Login
app.config['REMEMBER_COOKIE_DURATION'] = timedelta(days=30)
app.config['SESSION_COOKIE_SECURE'] = False  # Cambiar a True en producción con HTTPS
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'

# Habilitar CORS ANTES de definir las rutas
CORS(app)

# Inicializar base de datos ANTES de definir las rutas
db.init_app(app)

# Configurar Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_message = 'Por favor inicia sesión para acceder a esta página.'

@login_manager.user_loader
def load_user(user_id):
    return Usuario.query.get(int(user_id))

# FUNCIÓN PARA CREAR TABLAS Y DATOS INICIALES
def crear_tablas():
    """Crear todas las tablas automáticamente"""
    try:
        with app.app_context():
            # Crear todas las tablas definidas en models.py
            db.create_all()
            print("✓ Tablas creadas/verificadas exitosamente")
            
            # Verificar si existe usuario admin
            admin = Usuario.query.filter_by(Username='admin').first()
            
            if not admin:
                # Crear usuario administrador por defecto
                admin_user = Usuario(
                    Username='admin',
                    NombreCompleto='Administrador del Sistema',
                    Email='admin@empresa.com',
                    Rol='Admin',
                    Activo=True
                )
                admin_user.set_password('admin123')
                
                db.session.add(admin_user)
                db.session.commit()
                print("✓ Usuario administrador creado")
                print("  Username: admin")
                print("  Password: admin123")
            else:
                print("✓ Usuario administrador ya existe")
                
            # Verificar si existen clientes de ejemplo
            clientes_count = Cliente.query.count()
            
            if clientes_count == 0:
                # Crear clientes de ejemplo con fechas de vencimiento
                from datetime import date, timedelta
                
                clientes_ejemplo = [
                    Cliente(
                        NIT='12345678-9',
                        RazonSocial='Empresa Test S.A.S.',
                        NombreComercial='Test Company',
                        FechaVencimientoCertificado=date.today() + timedelta(days=60),
                        UsuarioModificacion='Sistema'
                    ),
                    Cliente(
                        NIT='98765432-1',
                        RazonSocial='Servicios Web LTDA',
                        NombreComercial='WebServ',
                        FechaVencimientoCertificado=date.today() + timedelta(days=15),  # Por vencer
                        UsuarioModificacion='Sistema'
                    ),
                    Cliente(
                        NIT='11111111-1',
                        RazonSocial='Corporación ABC',
                        NombreComercial='ABC Corp',
                        FechaVencimientoCertificado=date.today() - timedelta(days=10),  # Vencido
                        UsuarioModificacion='Sistema'
                    )
                ]
                
                for cliente in clientes_ejemplo:
                    db.session.add(cliente)
                
                db.session.commit()
                print("✓ Clientes de ejemplo creados")
            else:
                print(f"✓ Ya existen {clientes_count} clientes en la base de datos")
                
    except Exception as e:
        print(f"✗ Error creando tablas: {e}")
        return False
    
    return True

# RUTAS PRINCIPALES

@app.route('/')
@login_required
def home():
    """Página principal - requiere login"""
    return render_template('index.html', usuario=current_user)

@app.route('/dashboard')
@login_required
def dashboard():
    """Redirige al home (index.html)"""
    return redirect(url_for('home'))

@app.route('/test')
def test():
    return jsonify({
        'status': 'ok',
        'message': 'Servidor funcionando correctamente'
    })

@app.route('/test-db')
def test_db():
    try:
        with app.app_context():
            clientes_count = Cliente.query.count()
            usuarios_count = Usuario.query.count()
            return jsonify({
                'status': 'ok',
                'message': 'Base de datos conectada',
                'clientes': clientes_count,
                'usuarios': usuarios_count
            })
    except Exception as e:
        return jsonify({
            'status': 'error',
            'message': str(e)
        }), 500

@app.route('/init-db')
def init_database():
    """Ruta para inicializar la base de datos"""
    try:
        resultado = crear_tablas()
        if resultado:
            return jsonify({
                'success': True,
                'message': 'Base de datos inicializada correctamente'
            })
        else:
            return jsonify({
                'success': False,
                'message': 'Error al inicializar la base de datos'
            }), 500
    except Exception as e:
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# RUTA PARA COMPROBAR QUE LAS RUTAS ESTÁN REGISTRADAS
@app.route('/debug')
def debug():
    routes = []
    for rule in app.url_map.iter_rules():
        routes.append({
            'endpoint': rule.endpoint,
            'methods': list(rule.methods),
            'rule': str(rule)
        })
    return jsonify(routes)

# API DE CLIENTES

@app.route('/api/clientes', methods=['GET'])
@login_required
def get_clientes():
    try:
        print("EJECUTANDO get_clientes()")  # Debug
        
        # Parámetros de búsqueda
        nit = request.args.get('nit')
        razon_social = request.args.get('razon_social')
        nombre_comercial = request.args.get('nombre_comercial')
        
        print(f"Parámetros: nit={nit}, razon={razon_social}, nombre={nombre_comercial}")  # Debug
        
        # Construir query
        query = Cliente.query
        
        if nit:
            query = query.filter(Cliente.NIT.like(f'%{nit}%'))
        if razon_social:
            query = query.filter(Cliente.RazonSocial.like(f'%{razon_social}%'))
        if nombre_comercial:
            query = query.filter(Cliente.NombreComercial.like(f'%{nombre_comercial}%'))
        
        # Ejecutar query
        clientes = query.all()
        print(f"Clientes encontrados: {len(clientes)}")  # Debug
        
        # Convertir a diccionario usando el método to_dict()
        result = [cliente.to_dict() for cliente in clientes]
        
        return jsonify({
            'success': True,
            'clientes': result
        })
        
    except Exception as e:
        print(f"ERROR en get_clientes: {e}")  # Debug
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/clientes', methods=['POST'])
@login_required
def create_cliente():
    """Crear cliente - Permite múltiples locales por NIT"""
    try:
        data = request.get_json()
        
        if not data.get('NIT') or not data.get('RazonSocial') or not data.get('NombreComercial'):
            return jsonify({
                'success': False,
                'error': 'NIT, RazonSocial y NombreComercial son obligatorios'
            }), 400
        
        nit_limpio = str(data['NIT']).strip()
        nombre_comercial = str(data['NombreComercial']).strip()
        
        # IMPORTANTE: Buscar por NIT + NombreComercial (no solo NIT)
        existe = Cliente.query.filter(
            Cliente.NIT == nit_limpio,
            Cliente.NombreComercial == nombre_comercial
        ).first()
        
        if existe:
            return jsonify({
                'success': False,
                'error': f'Ya existe {nombre_comercial} con NIT {nit_limpio}'
            }), 400
        
        # Estado
        estado_activo = True
        if 'EstadoActivo' in data:
            val = data['EstadoActivo']
            if isinstance(val, bool):
                estado_activo = val
            elif isinstance(val, str):
                estado_activo = val.lower().strip() in ['true', '1', 'activo', 'active', 'si', 'yes']
        
        # Fecha
        fecha_vencimiento = None
        if data.get('FechaVencimientoCertificado'):
            try:
                fecha_str = str(data['FechaVencimientoCertificado']).strip()
                if fecha_str and fecha_str.lower() not in ['none', 'null', '']:
                    if '-' in fecha_str:
                        fecha_vencimiento = datetime.strptime(fecha_str, '%Y-%m-%d').date()
                    elif '/' in fecha_str:
                        fecha_vencimiento = datetime.strptime(fecha_str, '%d/%m/%Y').date()
                    else:
                        dias = int(float(fecha_str))
                        fecha_vencimiento = (datetime(1899, 12, 30) + timedelta(days=dias)).date()
            except:
                pass
        
        cliente = Cliente(
            NIT=nit_limpio,
            RazonSocial=str(data['RazonSocial']).strip(),
            NombreComercial=nombre_comercial,
            EstadoActivo=estado_activo,
            FechaVencimientoCertificado=fecha_vencimiento,
            UsuarioModificacion=current_user.Username,
            Observaciones=str(data.get('Observaciones', '')),
            TokenUser=str(data.get('TokenUser', '')),
            TokenPassword=str(data.get('TokenPassword', ''))
        )
        
        db.session.add(cliente)
        db.session.commit()
        
        print(f"✓ Creado: {nit_limpio} - {nombre_comercial}")
        
        return jsonify({
            'success': True,
            'message': 'Cliente creado exitosamente',
            'cliente': cliente.to_dict()
        }), 201
        
    except Exception as e:
        print(f"ERROR: {e}")
        import traceback
        traceback.print_exc()
        db.session.rollback()
        return jsonify({'success': False, 'error': str(e)}), 500

@app.route('/api/clientes/<int:cliente_id>/estado', methods=['PATCH'])
@login_required
def cambiar_estado(cliente_id):
    try:
        print(f"EJECUTANDO cambiar_estado({cliente_id})")  # Debug
        
        cliente = Cliente.query.get(cliente_id)
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'Cliente no encontrado'
            }), 404
        
        data = request.get_json()
        
        # Cambiar estado
        cliente.EstadoActivo = data.get('EstadoActivo', not cliente.EstadoActivo)
        cliente.UsuarioModificacion = current_user.Username
        cliente.FechaModificacion = datetime.utcnow()
        
        if data.get('Observaciones'):
            cliente.Observaciones = data['Observaciones']
        
        db.session.commit()
        
        print(f"Estado cambiado: {cliente.NIT} -> {cliente.EstadoActivo}")  # Debug
        
        return jsonify({
            'success': True,
            'message': 'Estado cambiado',
            'cliente': cliente.to_dict()
        })
        
    except Exception as e:
        print(f"ERROR en cambiar_estado: {e}")  # Debug
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/clientes/<int:cliente_id>', methods=['PUT'])
@login_required
def update_cliente(cliente_id):
    """Actualizar cliente"""
    try:
        cliente = Cliente.query.get(cliente_id)
        if not cliente:
            return jsonify({'success': False, 'error': 'Cliente no encontrado'}), 404
        
        data = request.get_json()
        
        if 'RazonSocial' not in data or 'NombreComercial' not in data:
            return jsonify({'success': False, 'error': 'Campos obligatorios faltantes'}), 400
        
        nuevo_nombre = str(data['NombreComercial']).strip()
        
        # Si cambia el nombre, verificar que no exista otro con ese NIT+Nombre
        if nuevo_nombre != cliente.NombreComercial:
            existe = Cliente.query.filter(
                Cliente.ClienteID != cliente_id,
                Cliente.NIT == cliente.NIT,
                Cliente.NombreComercial == nuevo_nombre
            ).first()
            if existe:
                return jsonify({
                    'success': False,
                    'error': f'Ya existe {nuevo_nombre} con NIT {cliente.NIT}'
                }), 400
        
        cliente.RazonSocial = str(data['RazonSocial']).strip()
        cliente.NombreComercial = nuevo_nombre
        
        if 'EstadoActivo' in data:
            val = data['EstadoActivo']
            if isinstance(val, bool):
                cliente.EstadoActivo = val
            elif isinstance(val, str):
                cliente.EstadoActivo = val.lower().strip() in ['true', '1', 'activo', 'active', 'si', 'yes']
        
        if 'Observaciones' in data:
            cliente.Observaciones = str(data['Observaciones']) if data['Observaciones'] else ''
        
        if 'TokenUser' in data:
            cliente.TokenUser = str(data['TokenUser']) if data['TokenUser'] else ''
        
        if 'TokenPassword' in data:
            cliente.TokenPassword = str(data['TokenPassword']) if data['TokenPassword'] else ''
        
        if 'FechaVencimientoCertificado' in data:
            fecha_val = data['FechaVencimientoCertificado']
            if fecha_val:
                try:
                    fecha_str = str(fecha_val).strip()
                    if fecha_str and fecha_str.lower() not in ['none', 'null', '']:
                        if '-' in fecha_str:
                            cliente.FechaVencimientoCertificado = datetime.strptime(fecha_str, '%Y-%m-%d').date()
                        elif '/' in fecha_str:
                            cliente.FechaVencimientoCertificado = datetime.strptime(fecha_str, '%d/%m/%Y').date()
                        else:
                            dias = int(float(fecha_str))
                            cliente.FechaVencimientoCertificado = (datetime(1899, 12, 30) + timedelta(days=dias)).date()
                    else:
                        cliente.FechaVencimientoCertificado = None
                except:
                    cliente.FechaVencimientoCertificado = None
            else:
                cliente.FechaVencimientoCertificado = None
        
        cliente.UsuarioModificacion = current_user.Username
        cliente.FechaModificacion = datetime.utcnow()
        
        db.session.commit()
        
        return jsonify({'success': True, 'message': 'Cliente actualizado', 'cliente': cliente.to_dict()})
        
    except Exception as e:
        print(f"ERROR: {e}")
        import traceback
        traceback.print_exc()
        db.session.rollback()
        return jsonify({'success': False, 'error': str(e)}), 500

@app.route('/api/clientes/<int:cliente_id>', methods=['DELETE'])
@login_required
def delete_cliente(cliente_id):
    """Eliminar cliente"""
    try:
        print(f"EJECUTANDO delete_cliente({cliente_id})")  # Debug
        
        cliente = Cliente.query.get(cliente_id)
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'Cliente no encontrado'
            }), 404
        
        # Guardar información del cliente antes de eliminarlo
        cliente_info = {
            'NIT': cliente.NIT,
            'RazonSocial': cliente.RazonSocial,
            'NombreComercial': cliente.NombreComercial
        }
        
        # Eliminar cliente
        db.session.delete(cliente)
        db.session.commit()
        
        print(f"Cliente eliminado: {cliente_info['NIT']}")  # Debug
        
        return jsonify({
            'success': True,
            'message': f'Cliente {cliente_info["NIT"]} eliminado exitosamente',
            'cliente_eliminado': cliente_info
        })
        
    except Exception as e:
        print(f"ERROR en delete_cliente: {e}")  # Debug
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# API DE USUARIOS

@app.route('/api/usuarios', methods=['GET'])
@login_required
def get_usuarios():
    try:
        usuarios = Usuario.query.all()
        result = [usuario.to_dict() for usuario in usuarios]
        return jsonify({
            'success': True,
            'usuarios': result
        })
    except Exception as e:
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/usuarios', methods=['POST'])
@login_required
def create_usuario():
    try:
        data = request.get_json()
        
        # Validar datos obligatorios
        if not data.get('Username') or not data.get('Password') or not data.get('NombreCompleto'):
            return jsonify({
                'success': False,
                'error': 'Username, Password y NombreCompleto son obligatorios'
            }), 400
        
        # Verificar si ya existe
        existe = Usuario.query.filter_by(Username=data['Username']).first()
        if existe:
            return jsonify({
                'success': False,
                'error': f'Ya existe un usuario con Username {data["Username"]}'
            }), 400
        
        # Crear usuario
        usuario = Usuario(
            Username=data['Username'],
            NombreCompleto=data['NombreCompleto'],
            Email=data.get('Email', ''),
            Rol=data.get('Rol', 'Usuario'),
            Activo=data.get('Activo', True)
        )
        usuario.set_password(data['Password'])
        
        db.session.add(usuario)
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': 'Usuario creado exitosamente',
            'usuario': usuario.to_dict()
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# RUTAS DE AUTENTICACIÓN

@app.route('/login', methods=['GET', 'POST'])
def login():
    # Si ya está autenticado, redirigir al home
    if current_user.is_authenticated:
        if request.method == 'GET':
            return redirect(url_for('home'))
        else:
            return jsonify({
                'success': True,
                'message': 'Ya está autenticado',
                'redirect': '/'
            })
    
    if request.method == 'POST':
        try:
            data = request.get_json()
            if not data:
                return jsonify({
                    'success': False,
                    'error': 'No se recibieron datos'
                }), 400
            
            username = data.get('username', '').strip()
            password = data.get('password', '')
            remember_me = data.get('rememberMe', False)
            
            print(f"Intento de login: {username}")  # Debug
            
            if not username or not password:
                return jsonify({
                    'success': False,
                    'error': 'Usuario y contraseña son obligatorios'
                }), 400
            
            # Buscar usuario
            usuario = Usuario.query.filter_by(Username=username).first()
            
            if usuario and usuario.check_password(password):
                if not usuario.Activo:
                    return jsonify({
                        'success': False,
                        'error': 'Usuario inactivo. Contacta al administrador.'
                    }), 401
                
                # Login exitoso
                login_user(usuario, remember=remember_me)
                usuario.UltimoAcceso = datetime.utcnow()
                db.session.commit()
                
                print(f"Login exitoso para: {username}")  # Debug
                
                return jsonify({
                    'success': True,
                    'message': 'Login exitoso',
                    'usuario': usuario.to_dict(),
                    'redirect': '/'
                })
            else:
                print(f"Login fallido para: {username}")  # Debug
                return jsonify({
                    'success': False,
                    'error': 'Usuario o contraseña incorrectos'
                }), 401
                
        except Exception as e:
            print(f"Error en login: {e}")
            return jsonify({
                'success': False,
                'error': 'Error interno del servidor'
            }), 500
    
    # GET request - mostrar formulario de login
    return render_template('login.html')

@app.route('/logout', methods=['POST'])
@login_required
def logout():
    print(f"Logout para usuario: {current_user.Username}")  # Debug
    logout_user()
    return jsonify({
        'success': True,
        'message': 'Logout exitoso'
    })

@app.route('/api/profile')
@login_required
def profile():
    return jsonify({
        'success': True,
        'usuario': current_user.to_dict()
    })

# RUTA PARA VERIFICAR SESIÓN ACTUAL
@app.route('/api/auth/check')
def check_auth():
    """Verificar si el usuario está autenticado"""
    if current_user.is_authenticated:
        return jsonify({
            'success': True,
            'authenticated': True,
            'usuario': current_user.to_dict()
        })
    else:
        return jsonify({
            'success': True,
            'authenticated': False
        })

# RUTA PARA CAMBIAR CONTRASEÑA
@app.route('/api/auth/change-password', methods=['POST'])
@login_required
def change_password():
    """Cambiar contraseña del usuario actual"""
    try:
        data = request.get_json()
        current_password = data.get('current_password')
        new_password = data.get('new_password')
        
        if not current_password or not new_password:
            return jsonify({
                'success': False,
                'error': 'Contraseña actual y nueva son obligatorias'
            }), 400
        
        if len(new_password) < 6:
            return jsonify({
                'success': False,
                'error': 'La nueva contraseña debe tener al menos 6 caracteres'
            }), 400
        
        # Verificar contraseña actual
        if not current_user.check_password(current_password):
            return jsonify({
                'success': False,
                'error': 'Contraseña actual incorrecta'
            }), 401
        
        # Cambiar contraseña
        current_user.set_password(new_password)
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': 'Contraseña cambiada exitosamente'
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# CONTEXTO GLOBAL PARA TEMPLATES
@app.context_processor
def inject_user():
    """Inyectar usuario actual en todos los templates"""
    return dict(current_user=current_user)

# Manejo de errores
@app.errorhandler(404)
def not_found(error):
    print(f"ERROR 404: {request.path}")  # Debug
    if request.path.startswith('/api/'):
        return jsonify({
            'success': False,
            'error': 'Ruta no encontrada',
            'path': request.path
        }), 404
    return render_template('404.html'), 404

@app.errorhandler(401)
def unauthorized(error):
    print(f"ERROR 401: {request.path}")  # Debug
    if request.path.startswith('/api/'):
        return jsonify({
            'success': False,
            'error': 'No autorizado - login requerido'
        }), 401
    return redirect(url_for('login'))

@app.errorhandler(500)
def internal_error(error):
    print(f"ERROR 500: {error}")
    db.session.rollback()
    if request.path.startswith('/api/'):
        return jsonify({
            'success': False,
            'error': 'Error interno del servidor'
        }), 500
    return render_template('500.html'), 500

# Crear tablas e iniciar servidor
if __name__ == '__main__':
    print("=" * 50)
    print("INICIANDO SERVIDOR...")
    print("=" * 50)
    
    # Crear tablas automáticamente
    print("Inicializando base de datos...")
    crear_tablas()
    
    # Mostrar rutas registradas
    print("\nRUTAS REGISTRADAS:")
    for rule in app.url_map.iter_rules():
        print(f"   {list(rule.methods)} {rule}")
    
    print("\n" + "=" * 50)
    print("Servidor: http://localhost:5000")
    print("Debug: http://localhost:5000/debug")
    print("Test: http://localhost:5000/test")
    print("Test DB: http://localhost:5000/test-db")
    print("Init DB: http://localhost:5000/init-db")
    print("Login: http://localhost:5000/login")
    print("=" * 50 + "\n")
    print("CREDENCIALES DE PRUEBA:")
    print("Usuario: admin")
    print("Contraseña: admin123")
    print("=" * 50 + "\n")
    
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=True,
        threaded=True
    )