"""
Sistema de Gestión Integral - Perfumados
Flask + SQLite con arquitectura modular y mejorada
"""
import os
from datetime import datetime, timedelta
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, flash
from flask_sqlalchemy import SQLAlchemy
import json
from functools import wraps

from models import (
    db, Usuario, Empleado, Venta, Asistencia, CajaDiaria,
    Producto, LOCALES_CONFIG, MARCAS_CONFIG
)
from utils import (
    calcular_distancia_haversine, validar_ubicacion_gps,
    login_required, admin_required, super_admin_required,
    formatear_moneda, formatear_fecha, get_stats_dia, get_stats_rango,
    validar_email, validar_rut,
    ahora_chile, hoy_chile, get_total_rango_locales, get_stats_consolidado_rango
)

# ============================================================================
# CONFIGURACIÓN
# ============================================================================
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-secret-key-change-in-production')

# Leer DB desde variable de entorno (MySQL en producción, SQLite en local)
_default_db = 'sqlite:///' + os.path.join(os.path.dirname(os.path.abspath(__file__)), 'instance', 'perfumados.db')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', _default_db)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max file upload

db.init_app(app)

# Registrar filtros Jinja2
@app.template_filter('moneda')
def filter_moneda(valor):
    return formatear_moneda(valor)

@app.template_filter('fecha')
def filter_fecha(fecha):
    return formatear_fecha(fecha)

@app.template_filter('selectattr_marca')
def filter_selectattr_marca(locales_list, marca_key, locales_config):
    """Filtra lista de locales por marca"""
    return [l for l in locales_list if locales_config.get(l, {}).get('marca') == marca_key]

@app.context_processor
def inject_locales():
    """Inyecta configuración de locales y marcas en templates"""
    return {'locales': LOCALES_CONFIG, 'marcas': MARCAS_CONFIG}

@app.context_processor
def inject_usuario():
    """Inyecta usuario actual en templates"""
    if 'user_id' in session:
        usuario = Usuario.query.get(session['user_id'])
        return {'usuario_actual': usuario}
    return {'usuario_actual': None}


# ============================================================================
# INICIALIZACIÓN BD
# ============================================================================
def init_db():
    """Inicializa la base de datos"""
    with app.app_context():
        db.create_all()

        # Crear usuario admin si no existe
        admin = Usuario.query.filter_by(email='admin@perfumados.cl').first()
        if not admin:
            admin = Usuario(
                nombre='Administrador',
                email='admin@perfumados.cl',
                rol='admin',
                local=None,
                activo=True
            )
            admin.set_password('admin123')
            db.session.add(admin)
            db.session.commit()
            print("✓ Usuario admin creado: admin@perfumados.cl / admin123")


# ============================================================================
# RUTAS - AUTENTICACIÓN
# ============================================================================
@app.route('/login', methods=['GET', 'POST'])
def login():
    """Login del sistema"""
    if request.method == 'POST':
        email = request.form.get('email', '').strip()
        password = request.form.get('password', '')

        if not email or not password:
            flash('Email y contraseña son requeridos', 'danger')
            return redirect(url_for('login'))

        usuario = Usuario.query.filter_by(email=email, activo=True).first()

        if usuario and usuario.check_password(password):
            session['user_id'] = usuario.id
            session['user_email'] = usuario.email
            session['user_rol'] = usuario.rol
            usuario.ultimo_acceso = ahora_chile()
            db.session.commit()
            flash(f'Bienvenido {usuario.nombre}', 'success')
            return redirect(url_for('dashboard'))
        else:
            flash('Email o contraseña incorrectos', 'danger')

    return render_template('login.html')


@app.route('/logout')
def logout():
    """Logout del sistema"""
    session.clear()
    flash('Sesión cerrada', 'info')
    return redirect(url_for('login'))


# ============================================================================
# RUTAS - DASHBOARD
# ============================================================================
@app.route('/')
@app.route('/dashboard')
@login_required
def dashboard():
    """Dashboard principal"""
    usuario = Usuario.query.get(session['user_id'])
    hoy = hoy_chile()

    # Determinar locales a mostrar
    if usuario.local:
        locales_mostrar = [usuario.local]
    else:
        locales_mostrar = list(LOCALES_CONFIG.keys())

    # Stats de HOY por local
    stats_por_local = {}
    for local in locales_mostrar:
        stats_por_local[local] = get_stats_dia(local, hoy)

    # Total consolidado hoy
    total_consolidado = sum(s['total_monto'] for s in stats_por_local.values())
    total_ventas = sum(s['total_ventas'] for s in stats_por_local.values())

    # Totales por marca hoy
    totales_por_marca = {}
    for marca_key in MARCAS_CONFIG:
        totales_por_marca[marca_key] = sum(
            stats_por_local[l]['total_monto']
            for l in locales_mostrar
            if LOCALES_CONFIG.get(l, {}).get('marca') == marca_key
        )

    # ── Acumulado SEMANA (lunes a hoy) ──────────────────────────────────────
    inicio_semana = hoy - timedelta(days=hoy.weekday())
    stats_semana = get_stats_consolidado_rango(locales_mostrar, inicio_semana, hoy)

    # ── Acumulado MES (día 1 a hoy) ─────────────────────────────────────────
    inicio_mes = hoy.replace(day=1)
    stats_mes = get_stats_consolidado_rango(locales_mostrar, inicio_mes, hoy)

    # ── Datos para gráficos ─────────────────────────────────────────────────
    # Barras: ventas por local hoy
    chart_labels = [LOCALES_CONFIG[l]['nombre'].replace(
        LOCALES_CONFIG[l].get('nombre', ''), LOCALES_CONFIG[l]['nombre']
    ) for l in locales_mostrar]
    # Nombres cortos para el gráfico
    chart_labels_cortos = []
    for l in locales_mostrar:
        cfg = LOCALES_CONFIG[l]
        nombre = cfg['nombre']
        marca_nombre = MARCAS_CONFIG.get(cfg['marca'], {}).get('nombre', '')
        nombre_corto = nombre.replace(marca_nombre + ' ', '').replace(marca_nombre, '').strip() or nombre
        chart_labels_cortos.append(nombre_corto[:20])

    chart_data_hoy = [stats_por_local[l]['total_monto'] for l in locales_mostrar]
    chart_colors = [LOCALES_CONFIG[l]['color'] for l in locales_mostrar]

    # Dona: desglose medios de pago (hoy, todos los locales)
    pago_hoy = {
        'efectivo': sum(stats_por_local[l]['efectivo'] for l in locales_mostrar),
        'debito':   sum(stats_por_local[l]['debito'] for l in locales_mostrar),
        'credito':  sum(stats_por_local[l]['credito'] for l in locales_mostrar),
        'transferencia': sum(stats_por_local[l]['transferencia'] for l in locales_mostrar),
        'otros':    sum(stats_por_local[l]['otros'] for l in locales_mostrar),
    }

    return render_template(
        'dashboard.html',
        hoy=hoy,
        stats_por_local=stats_por_local,
        total_consolidado=total_consolidado,
        total_ventas=total_ventas,
        locales_mostrar=locales_mostrar,
        totales_por_marca=totales_por_marca,
        stats_semana=stats_semana,
        stats_mes=stats_mes,
        inicio_semana=inicio_semana,
        inicio_mes=inicio_mes,
        chart_labels=chart_labels_cortos,
        chart_data_hoy=chart_data_hoy,
        chart_colors=chart_colors,
        pago_hoy=pago_hoy,
    )


# ============================================================================
# RUTAS - VENTAS
# ============================================================================
@app.route('/ventas/<local>')
@login_required
def ventas(local):
    """Lista de ventas de un local"""
    if local not in LOCALES_CONFIG:
        flash('Local no válido', 'danger')
        return redirect(url_for('dashboard'))

    usuario = Usuario.query.get(session['user_id'])

    # Validar acceso al local
    if usuario.local and usuario.local != local and usuario.rol != 'admin':
        flash('No tienes permiso para este local', 'danger')
        return redirect(url_for('dashboard'))

    # Filtros
    fecha_from = request.args.get('fecha_from', (hoy_chile() - timedelta(days=7)).isoformat())
    fecha_to = request.args.get('fecha_to', hoy_chile().isoformat())
    forma_pago = request.args.get('forma_pago', '')
    turno = request.args.get('turno', '')

    query = Venta.query.filter_by(local=local)

    if fecha_from:
        query = query.filter(Venta.fecha >= datetime.fromisoformat(fecha_from).date())
    if fecha_to:
        query = query.filter(Venta.fecha <= datetime.fromisoformat(fecha_to).date())
    if forma_pago:
        query = query.filter_by(forma_pago=forma_pago)
    if turno:
        query = query.filter_by(turno=turno)

    ventas = query.order_by(Venta.fecha.desc(), Venta.creado.desc()).all()

    # Estadísticas
    total = sum(v.total for v in ventas)
    total_por_forma = {
        'efectivo': sum(v.total for v in ventas if v.forma_pago == 'efectivo'),
        'debito': sum(v.total for v in ventas if v.forma_pago == 'debito'),
        'credito': sum(v.total for v in ventas if v.forma_pago == 'credito'),
        'transferencia': sum(v.total for v in ventas if v.forma_pago == 'transferencia'),
        'otros': sum(v.total for v in ventas if v.forma_pago not in ('efectivo', 'debito', 'credito', 'transferencia')),
        'tarjeta': sum(v.total for v in ventas if v.forma_pago in ('debito', 'credito', 'tarjeta')),
    }

    return render_template(
        'ventas.html',
        local=local,
        ventas=ventas,
        total=total,
        total_por_forma=total_por_forma,
        fecha_from=fecha_from,
        fecha_to=fecha_to,
        forma_pago_sel=forma_pago,
        turno_sel=turno
    )


@app.route('/ventas/<local>/nueva', methods=['GET', 'POST'])
@login_required
@admin_required
def nueva_venta(local):
    """Crear nueva venta"""
    if local not in LOCALES_CONFIG:
        return redirect(url_for('dashboard'))

    if request.method == 'POST':
        try:
            venta = Venta(
                local=local,
                fecha=datetime.fromisoformat(request.form['fecha']).date() if request.form.get('fecha') else hoy_chile(),
                producto=request.form['producto'],
                cantidad=int(request.form.get('cantidad', 1)),
                precio_unitario=float(request.form['precio_unitario']),
                total=float(request.form['precio_unitario']) * int(request.form.get('cantidad', 1)),
                descuento=float(request.form.get('descuento', 0)),
                forma_pago=request.form['forma_pago'],
                vendedor=request.form.get('vendedor', ''),
                turno=request.form['turno'],
                registrado_por_id=session['user_id'],
                notas=request.form.get('notas', '')
            )
            venta.total -= venta.descuento

            db.session.add(venta)
            db.session.commit()
            flash(f'Venta registrada: ${venta.total:,.0f}', 'success')
            return redirect(url_for('ventas', local=local))
        except Exception as e:
            db.session.rollback()
            flash(f'Error al registrar venta: {str(e)}', 'danger')

    return render_template('nueva_venta.html', local=local)


@app.route('/seleccionar-local')
@login_required
@admin_required
def seleccionar_local():
    """Pantalla para elegir el local antes de registrar turno"""
    usuario = Usuario.query.get(session['user_id'])
    if usuario.local:
        # Si el usuario tiene un local asignado, va directo
        return redirect(url_for('registro_turno', local=usuario.local))
    return render_template('seleccionar_local.html')


@app.route('/ventas/<local>/turno', methods=['GET', 'POST'])
@login_required
@admin_required
def registro_turno(local):
    """Registro de totales del turno (cierre de caja simplificado)"""
    if local not in LOCALES_CONFIG:
        return redirect(url_for('dashboard'))

    if request.method == 'POST':
        try:
            fecha = datetime.fromisoformat(request.form['fecha']).date()
            turno = request.form['turno']
            vendedor = request.form.get('vendedor', '')
            notas = request.form.get('notas', '')

            medios = {
                'efectivo':      float(request.form.get('efectivo', 0) or 0),
                'debito':        float(request.form.get('debito', 0) or 0),
                'credito':       float(request.form.get('credito', 0) or 0),
                'transferencia': float(request.form.get('transferencia', 0) or 0),
                'otros':         float(request.form.get('otros', 0) or 0),
            }

            total_turno = sum(medios.values())
            if total_turno <= 0:
                flash('Debes ingresar al menos un monto mayor a 0', 'danger')
                return redirect(url_for('registro_turno', local=local))

            # Crear una Venta por cada medio de pago con monto > 0
            registros = 0
            for forma_pago, monto in medios.items():
                if monto > 0:
                    venta = Venta(
                        local=local,
                        fecha=fecha,
                        producto=f'Cierre Turno {turno}',
                        cantidad=1,
                        precio_unitario=monto,
                        total=monto,
                        descuento=0,
                        forma_pago=forma_pago,
                        vendedor=vendedor,
                        turno=turno,
                        registrado_por_id=session['user_id'],
                        notas=f'[CIERRE_TURNO] {notas}'.strip()
                    )
                    db.session.add(venta)
                    registros += 1

            db.session.commit()
            flash(f'Turno {turno} registrado — Total: ${total_turno:,.0f} ({registros} medios de pago)', 'success')
            return redirect(url_for('ventas', local=local))

        except Exception as e:
            db.session.rollback()
            flash(f'Error al registrar: {str(e)}', 'danger')

    return render_template('registro_turno.html', local=local)


@app.route('/ventas/<local>/importar', methods=['POST'])
@login_required
@admin_required
def importar_ventas(local):
    """Importar ventas desde Excel"""
    if local not in LOCALES_CONFIG:
        return jsonify({'error': 'Local no válido'}), 400

    try:
        from openpyxl import load_workbook

        if 'archivo' not in request.files:
            return jsonify({'error': 'No hay archivo'}), 400

        archivo = request.files['archivo']
        if not archivo.filename.endswith('.xlsx'):
            return jsonify({'error': 'Archivo debe ser .xlsx'}), 400

        # Procesar Excel
        wb = load_workbook(archivo)
        ws = wb.active

        # Buscar DÍA y TURNO
        dia_celda = None
        turno_celda = None
        cant_col = producto_col = precio_col = None

        for row in ws.iter_rows(max_row=10):
            for i, cell in enumerate(row):
                if cell.value and str(cell.value).upper().strip() == 'DIA':
                    dia_celda = row[i + 1] if i + 1 < len(row) else None
                if cell.value and str(cell.value).upper().strip() == 'TURNO':
                    turno_celda = row[i + 1] if i + 1 < len(row) else None
                if cell.value and str(cell.value).upper().strip() == 'CANT':
                    cant_col = i
                if cell.value and str(cell.value).upper().strip() == 'PRODUCTO':
                    producto_col = i
                if cell.value and str(cell.value).upper().strip() in ['PRECIO', 'VALOR', 'UNIT']:
                    precio_col = i

        if not all([cant_col is not None, producto_col is not None, precio_col is not None]):
            return jsonify({'error': 'Formato de Excel inválido'}), 400

        fecha = datetime.fromisoformat(str(dia_celda.value)).date() if dia_celda else hoy_chile()
        turno = str(turno_celda.value).upper()[:2] if turno_celda else 'AM'

        # Importar filas
        importados = 0
        for row in ws.iter_rows(min_row=ws.max_row - 100):
            if not row[cant_col].value:
                continue

            try:
                cantidad = int(row[cant_col].value)
                producto = str(row[producto_col].value)
                precio = float(row[precio_col].value)

                if precio > 0:
                    venta = Venta(
                        local=local,
                        fecha=fecha,
                        producto=producto,
                        cantidad=cantidad,
                        precio_unitario=precio,
                        total=cantidad * precio,
                        forma_pago='efectivo',
                        turno=turno,
                        registrado_por_id=session['user_id']
                    )
                    db.session.add(venta)
                    importados += 1
            except:
                continue

        db.session.commit()
        return jsonify({'success': True, 'importados': importados})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


# ============================================================================
# RUTAS - EMPLEADOS
# ============================================================================
@app.route('/empleados')
@login_required
@admin_required
def empleados():
    """Lista de empleados"""
    usuario = Usuario.query.get(session['user_id'])

    if usuario.local and usuario.rol != 'admin':
        empleados_list = Empleado.query.filter_by(local=usuario.local, activo=True).all()
    else:
        empleados_list = Empleado.query.filter_by(activo=True).all()

    return render_template('empleados.html', empleados=empleados_list)


@app.route('/empleados/nuevo', methods=['GET', 'POST'])
@login_required
@admin_required
def nuevo_empleado():
    """Crear nuevo empleado"""
    if request.method == 'POST':
        try:
            if not validar_rut(request.form['rut']):
                flash('RUT inválido', 'danger')
                return redirect(url_for('nuevo_empleado'))

            empleado = Empleado(
                nombre=request.form['nombre'],
                rut=request.form['rut'].upper(),
                cargo=request.form['cargo'],
                local=request.form['local'],
                telefono=request.form.get('telefono', ''),
                email=request.form.get('email', ''),
                salario_base=float(request.form.get('salario_base', 0)),
                activo=True
            )
            db.session.add(empleado)
            db.session.commit()
            flash(f'Empleado {empleado.nombre} creado', 'success')
            return redirect(url_for('empleados'))
        except Exception as e:
            db.session.rollback()
            flash(f'Error: {str(e)}', 'danger')

    return render_template('nuevo_empleado.html')


@app.route('/empleados/<empleado_id>/editar', methods=['GET', 'POST'])
@login_required
@admin_required
def editar_empleado(empleado_id):
    """Editar empleado"""
    empleado = Empleado.query.get(empleado_id)
    if not empleado:
        flash('Empleado no encontrado', 'danger')
        return redirect(url_for('empleados'))

    if request.method == 'POST':
        try:
            empleado.nombre = request.form['nombre']
            empleado.cargo = request.form['cargo']
            empleado.telefono = request.form.get('telefono', '')
            empleado.email = request.form.get('email', '')
            empleado.salario_base = float(request.form.get('salario_base', 0))
            db.session.commit()
            flash('Empleado actualizado', 'success')
            return redirect(url_for('empleados'))
        except Exception as e:
            db.session.rollback()
            flash(f'Error: {str(e)}', 'danger')

    return render_template('editar_empleado.html', empleado=empleado)


@app.route('/empleados/<empleado_id>/eliminar', methods=['POST'])
@login_required
@admin_required
def eliminar_empleado(empleado_id):
    """Desactivar empleado (soft delete)"""
    empleado = Empleado.query.get(empleado_id)
    if empleado:
        empleado.activo = False
        db.session.commit()
        flash(f'Empleado {empleado.nombre} desactivado', 'success')
    return redirect(url_for('empleados'))


# ============================================================================
# RUTAS - ASISTENCIA
# ============================================================================
@app.route('/asistencia')
@login_required
def asistencia():
    """Control de asistencia"""
    empleados = Empleado.query.filter_by(activo=True).all()
    hoy = hoy_chile()

    # Registros de hoy
    registros_hoy = Asistencia.query.filter_by(fecha=hoy).all()

    return render_template(
        'asistencia.html',
        empleados=empleados,
        hoy=hoy,
        registros_hoy=registros_hoy,
        locales=LOCALES_CONFIG
    )


@app.route('/asistencia/registrar', methods=['POST'])
@login_required
def registrar_asistencia():
    """Registrar entrada/salida con validación GPS"""
    try:
        data = request.get_json()

        empleado_id = data.get('empleado_id')
        local = data.get('local')
        lat = float(data.get('lat'))
        lng = float(data.get('lng'))
        tipo = data.get('tipo')  # 'entrada' o 'salida'

        # Validaciones
        empleado = Empleado.query.get(empleado_id)
        if not empleado or not empleado.activo:
            return jsonify({'error': 'Empleado no válido'}), 400

        # Validar ubicación (admins y supervisores pueden saltarse el GPS)
        usuario = Usuario.query.get(session['user_id'])
        es_admin = usuario and usuario.rol in ['admin', 'supervisor']

        validacion = validar_ubicacion_gps(local, lat, lng)
        if not validacion['valido'] and not es_admin:
            return jsonify({
                'error': validacion['mensaje'],
                'distancia': validacion['distancia']
            }), 403
        elif not validacion['valido'] and es_admin:
            # Admin puede registrar fuera del rango, pero se deja nota
            validacion['distancia'] = validacion.get('distancia', 0)

        hoy = hoy_chile()
        ahora = ahora_chile()

        # Buscar registro del día
        registro = Asistencia.query.filter_by(
            empleado_id=empleado_id,
            fecha=hoy
        ).first()

        if not registro:
            if tipo == 'salida':
                return jsonify({'error': 'Debes marcar entrada primero'}), 400

            registro = Asistencia(
                empleado_id=empleado_id,
                local=local,
                fecha=hoy,
                entrada=ahora,
                lat_entrada=lat,
                lng_entrada=lng,
                distancia_entrada=validacion['distancia'],
                valida=True
            )
            db.session.add(registro)
        else:
            if tipo == 'entrada':
                return jsonify({'error': 'Ya marcaste entrada hoy'}), 400

            registro.salida = ahora
            registro.lat_salida = lat
            registro.lng_salida = lng
            registro.distancia_salida = validacion['distancia']

        db.session.commit()

        return jsonify({
            'success': True,
            'mensaje': f'{tipo.capitalize()} registrada a las {ahora.strftime("%H:%M")}',
            'distancia': validacion['distancia'],
            'duracion': registro.duracion_horas() if registro.salida else None
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/asistencia/reporte')
@login_required
@admin_required
def reporte_asistencia():
    """Reporte de asistencia por rango de fechas"""
    fecha_from = request.args.get('fecha_from', (hoy_chile() - timedelta(days=30)).isoformat())
    fecha_to = request.args.get('fecha_to', hoy_chile().isoformat())
    empleado_id = request.args.get('empleado_id', '')

    query = Asistencia.query.filter(
        Asistencia.fecha >= datetime.fromisoformat(fecha_from).date(),
        Asistencia.fecha <= datetime.fromisoformat(fecha_to).date()
    )

    if empleado_id:
        query = query.filter_by(empleado_id=empleado_id)

    registros = query.order_by(Asistencia.fecha.desc()).all()
    empleados = Empleado.query.filter_by(activo=True).all()

    return render_template(
        'reporte_asistencia.html',
        registros=registros,
        empleados=empleados,
        fecha_from=fecha_from,
        fecha_to=fecha_to,
        empleado_sel=empleado_id
    )


# ============================================================================
# RUTAS - USUARIOS
# ============================================================================
@app.route('/usuarios')
@login_required
@super_admin_required
def usuarios():
    """Lista de usuarios (solo admin)"""
    usuarios_list = Usuario.query.order_by(Usuario.creado.desc()).all()
    return render_template('usuarios.html', usuarios=usuarios_list)


@app.route('/usuarios/nuevo', methods=['GET', 'POST'])
@login_required
@super_admin_required
def nuevo_usuario():
    """Crear nuevo usuario"""
    if request.method == 'POST':
        try:
            if not validar_email(request.form['email']):
                flash('Email no válido', 'danger')
                return redirect(url_for('nuevo_usuario'))

            if Usuario.query.filter_by(email=request.form['email']).first():
                flash('Email ya existe', 'danger')
                return redirect(url_for('nuevo_usuario'))

            usuario = Usuario(
                nombre=request.form['nombre'],
                email=request.form['email'],
                rol=request.form['rol'],
                local=request.form.get('local') or None,
                activo=True
            )
            usuario.set_password(request.form['password'])

            db.session.add(usuario)
            db.session.commit()
            flash(f'Usuario {usuario.email} creado', 'success')
            return redirect(url_for('usuarios'))
        except Exception as e:
            db.session.rollback()
            flash(f'Error: {str(e)}', 'danger')

    return render_template('nuevo_usuario.html')


# ============================================================================
# RUTAS - REPORTES
# ============================================================================
@app.route('/reportes')
@login_required
@admin_required
def reportes():
    """Reportes consolidados"""
    fecha_from = request.args.get('fecha_from', (hoy_chile() - timedelta(days=30)).isoformat())
    fecha_to = request.args.get('fecha_to', hoy_chile().isoformat())
    # Usar el primer local válido como default (evita KeyError si cambia la config)
    primer_local = list(LOCALES_CONFIG.keys())[0]
    local_sel = request.args.get('local', primer_local)
    if local_sel not in LOCALES_CONFIG:
        local_sel = primer_local

    fecha_inicio = datetime.fromisoformat(fecha_from).date()
    fecha_fin = datetime.fromisoformat(fecha_to).date()

    stats = get_stats_rango(local_sel, fecha_inicio, fecha_fin)

    return render_template(
        'reportes.html',
        stats=stats,
        fecha_from=fecha_from,
        fecha_to=fecha_to,
        local_sel=local_sel
    )


# ============================================================================
# RUTA - REPORTE PDF
# ============================================================================
@app.route('/reportes/pdf')
@login_required
@admin_required
def reporte_pdf():
    """Genera una página de reporte lista para imprimir/guardar como PDF"""
    fecha_from = request.args.get('fecha_from', (hoy_chile() - timedelta(days=30)).isoformat())
    fecha_to   = request.args.get('fecha_to',   hoy_chile().isoformat())
    local_sel  = request.args.get('local', list(LOCALES_CONFIG.keys())[0])
    if local_sel not in LOCALES_CONFIG:
        local_sel = list(LOCALES_CONFIG.keys())[0]

    fecha_inicio = datetime.fromisoformat(fecha_from).date()
    fecha_fin    = datetime.fromisoformat(fecha_to).date()
    stats        = get_stats_rango(local_sel, fecha_inicio, fecha_fin)

    return render_template(
        'reporte_pdf.html',
        stats=stats,
        fecha_from=fecha_from,
        fecha_to=fecha_to,
        local_sel=local_sel,
        generado=ahora_chile(),
    )


# ============================================================================
# RUTA MÓVIL DE ASISTENCIA (sin login — para empleados desde el celular)
# ============================================================================
@app.route('/marcar', methods=['GET', 'POST'])
def marcar_asistencia_movil():
    """
    Página pública móvil donde los empleados marcan entrada/salida.
    - No requiere sesión de usuario del sistema.
    - Verifica identidad con los últimos 4 dígitos numéricos del RUT.
    - Guarda fingerprint del dispositivo para prevenir fraude.
    """
    if request.method == 'POST':
        try:
            data = request.get_json()

            empleado_id  = data.get('empleado_id', '')
            local        = data.get('local', '')
            lat          = float(data.get('lat', 0))
            lng          = float(data.get('lng', 0))
            tipo         = data.get('tipo', '')       # 'entrada' | 'salida'
            rut_pin      = data.get('rut_pin', '').strip()
            device_fp    = str(data.get('device_fp', ''))[:512]
            device_info  = str(data.get('device_info', ''))[:255]

            # Validar empleado
            empleado = Empleado.query.get(empleado_id)
            if not empleado or not empleado.activo:
                return jsonify({'error': 'Empleado no encontrado'}), 400

            if local not in LOCALES_CONFIG:
                return jsonify({'error': 'Local no válido'}), 400

            # ── Verificar PIN (últimos 4 dígitos numéricos del RUT) ──────────
            rut_digits = ''.join(c for c in empleado.rut if c.isdigit())
            pin_correcto = rut_digits[-4:] if len(rut_digits) >= 4 else rut_digits
            if rut_pin != pin_correcto:
                return jsonify({'error': '❌ PIN incorrecto. Ingresa los últimos 4 dígitos de tu RUT (solo números)'}), 403

            # ── Anti-fraude: mismo dispositivo, distinto empleado ────────────
            hoy = hoy_chile()
            if device_fp:
                otro = Asistencia.query.filter(
                    Asistencia.fecha == hoy,
                    Asistencia.device_fingerprint == device_fp,
                    Asistencia.empleado_id != empleado_id
                ).first()
                if otro:
                    return jsonify({
                        'error': '⚠️ Este dispositivo ya fue usado hoy por otro empleado. Contacta a tu supervisor.'
                    }), 403

            # ── Validar GPS (advertencia, no bloqueo — coordenadas pueden estar mal) ──
            validacion = validar_ubicacion_gps(local, lat, lng)
            gps_aviso = None
            if not validacion['valido']:
                gps_aviso = f"⚠️ GPS registrado fuera del rango ({round(validacion['distancia'])}m)"

            ahora = ahora_chile()

            # ── Buscar o crear registro de asistencia ────────────────────────
            registro = Asistencia.query.filter_by(
                empleado_id=empleado_id,
                fecha=hoy
            ).first()

            if not registro:
                if tipo == 'salida':
                    return jsonify({'error': 'Debes marcar entrada primero'}), 400
                registro = Asistencia(
                    empleado_id=empleado_id,
                    local=local,
                    fecha=hoy,
                    entrada=ahora,
                    lat_entrada=lat,
                    lng_entrada=lng,
                    distancia_entrada=validacion['distancia'],
                    device_fingerprint=device_fp,
                    device_info=device_info,
                    valida=validacion['valido']
                )
                db.session.add(registro)
            else:
                if tipo == 'entrada':
                    return jsonify({'error': 'Ya registraste tu entrada hoy'}), 400
                registro.salida = ahora
                registro.lat_salida = lat
                registro.lng_salida = lng
                registro.distancia_salida = validacion['distancia']

            db.session.commit()

            return jsonify({
                'success': True,
                'aviso': gps_aviso,
                'mensaje': f'{tipo.capitalize()} registrada a las {ahora.strftime("%H:%M")}',
                'empleado': empleado.nombre,
                'distancia': round(validacion['distancia']),
                'hora': ahora.strftime('%H:%M'),
            })

        except Exception as e:
            db.session.rollback()
            return jsonify({'error': str(e)}), 500

    # GET — mostrar formulario móvil
    empleados_list = Empleado.query.filter_by(activo=True).order_by(Empleado.nombre).all()
    return render_template('marcar_asistencia.html', empleados=empleados_list)


# ============================================================================
# MANEJO DE ERRORES
# ============================================================================
@app.errorhandler(404)
def not_found(error):
    return render_template('error.html', codigo=404, mensaje='Página no encontrada'), 404


@app.errorhandler(500)
def server_error(error):
    return render_template('error.html', codigo=500, mensaje='Error interno del servidor'), 500


# ============================================================================
# INICIALIZACIÓN
# ============================================================================
if __name__ == '__main__':
    init_db()
    app.run(debug=True, host='0.0.0.0', port=5000)
