from flask import Flask, request, jsonify, send_file, render_template, send_from_directory
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
from datetime import datetime, timedelta
import calendar
import logging
import os
from pathlib import Path
import io
import pandas as pd
from typing import Dict, List, Optional, Any
import json

# Configuración de logging para producción
log_dir = '/var/www/html/TransmisionesMig/logs'
os.makedirs(log_dir, exist_ok=True)

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(os.path.join(log_dir, 'reporte_mensual.log')),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# Crear la aplicación Flask
app = Flask(__name__)

# CONFIGURACIÓN DE BASE DE DATOS
DB_SERVER = 'localhost'
DB_PORT = '1433'
DB_DATABASE = 'TRANSMISIONESMIG'
DB_USERNAME = 'sa'
DB_PASSWORD = 'Sistemas123*/'
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'] = 'K8m2#D9v$L4x@R7n*W5q&F1s!P6j%T3y^B8e@N7k$H4m*V9r&L2x#Q5w'
app.config['DEBUG'] = False

# Habilitar CORS
CORS(app)

# Inicializar SQLAlchemy
db = SQLAlchemy(app)

# MODELO DE EMPRESAS CLIENTES
class EmpresaCliente(db.Model):
    __tablename__ = 'Empresas_Clientes'
    
    ID = db.Column(db.Integer, primary_key=True)
    RazonSocial = db.Column(db.String(255), nullable=False)
    NombreComercial = db.Column(db.String(255), nullable=False)
    NIT = db.Column(db.String(20), unique=True, nullable=False)
    Email = db.Column(db.String(255))
    Telefono = db.Column(db.String(50))
    Direccion = db.Column(db.String(500))
    Activo = db.Column(db.Boolean, default=True)
    FechaCreacion = db.Column(db.DateTime, default=datetime.utcnow)
    FechaModificacion = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Relación con reportes
    reportes = db.relationship('ControlReportes', backref='empresa_cliente', lazy='dynamic')
    
    def to_dict(self):
        return {
            'id': self.ID,
            'razon_social': self.RazonSocial,
            'nombre_comercial': self.NombreComercial,
            'nit': self.NIT,
            'email': self.Email,
            'telefono': self.Telefono,
            'direccion': self.Direccion,
            'activo': self.Activo,
            'fecha_creacion': self.FechaCreacion.isoformat() if self.FechaCreacion else None,
            'fecha_modificacion': self.FechaModificacion.isoformat() if self.FechaModificacion else None
        }

# MODELO MODIFICADO PARA REPORTES (CON CLIENTE)
class ControlReportes(db.Model):
    __tablename__ = 'Control_Reportes'
    
    ID = db.Column(db.Integer, primary_key=True)
    Periodo = db.Column(db.String(7), nullable=False)
    ClienteID = db.Column(db.Integer, db.ForeignKey('Empresas_Clientes.ID'), nullable=False)
    FechaEnvio = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    Enviado = db.Column(db.Boolean, default=True)
    Observaciones = db.Column(db.String(500))
    TotalDocumentos = db.Column(db.Integer, default=0)
    DocumentosExitosos = db.Column(db.Integer, default=0)
    ValorTotal = db.Column(db.Numeric(18, 2), default=0)
    TasaExito = db.Column(db.Numeric(5, 2), default=0)
    ContenidoCompleto = db.Column(db.Text)
    DetalleFacturas = db.Column(db.Text)
    DetalleGastos = db.Column(db.Text)
    
    # NUEVA COLUMNA PARA MARCAR SI YA FUE FACTURADO
    Facturado = db.Column(db.Boolean, default=False)
    FechaFacturacion = db.Column(db.DateTime, nullable=True)
    NumeroFactura = db.Column(db.String(50), nullable=True)
    
    # Índice único por período y cliente
    __table_args__ = (db.UniqueConstraint('Periodo', 'ClienteID', name='_periodo_cliente_uc'),)
    
    def to_dict(self):
        cliente_info = None
        if self.empresa_cliente:
            cliente_info = {
                'id': self.empresa_cliente.ID,
                'razon_social': self.empresa_cliente.RazonSocial,
                'nombre_comercial': self.empresa_cliente.NombreComercial,
                'nit': self.empresa_cliente.NIT,
                'email': self.empresa_cliente.Email,
                'telefono': self.empresa_cliente.Telefono,
                'direccion': self.empresa_cliente.Direccion,
                'activo': self.empresa_cliente.Activo
            }
        
        return {
            'id': self.ID,
            'periodo': self.Periodo,
            'cliente_id': self.ClienteID,
            'cliente': cliente_info,
            'fecha_envio': self.FechaEnvio.isoformat() if self.FechaEnvio else None,
            'total_documentos': int(self.TotalDocumentos or 0),
            'documentos_exitosos': int(self.DocumentosExitosos or 0),
            'valor_total': float(self.ValorTotal or 0),
            'tasa_exito': float(self.TasaExito or 0),
            'observaciones': self.Observaciones,
            'status': 'completed' if self.Enviado else 'pending',
            'contenido_completo': self.ContenidoCompleto,
            'detalle_facturas': json.loads(self.DetalleFacturas) if self.DetalleFacturas else None,
            'detalle_gastos': json.loads(self.DetalleGastos) if self.DetalleGastos else None,
            
            # NUEVA INFORMACIÓN DE FACTURACIÓN
            'facturado': bool(self.Facturado),
            'fecha_facturacion': self.FechaFacturacion.isoformat() if self.FechaFacturacion else None,
            'numero_factura': self.NumeroFactura,
            'estado_facturacion': 'Facturado' if self.Facturado else 'Pendiente',
            
            # INFORMACIÓN PARA CARTERA
            'cliente_info_resumida': f"{cliente_info['nombre_comercial']} ({cliente_info['nit']})" if cliente_info else "Cliente no encontrado",
            'cliente_razon_social': cliente_info['razon_social'] if cliente_info else None,
            'cliente_nombre_comercial': cliente_info['nombre_comercial'] if cliente_info else None,
            'cliente_nit': cliente_info['nit'] if cliente_info else None
        }

@app.route('/api/facturacion-por-cliente', methods=['GET'])
def get_facturacion_por_cliente():
    """Obtiene resumen de facturación agrupado por cliente - útil para cartera"""
    try:
        year = request.args.get('year', datetime.now().year)
        month = request.args.get('month')
        
        # Construir filtros
        filters = []
        if year:
            if month:
                period_filter = f"{year}-{str(month).zfill(2)}"
                filters.append(ControlReportes.Periodo == period_filter)
            else:
                filters.append(ControlReportes.Periodo.like(f"{year}-%"))
        
        # Consultar reportes con información de cliente
        query = db.session.query(ControlReportes, EmpresaCliente).join(
            EmpresaCliente, ControlReportes.ClienteID == EmpresaCliente.ID
        ).filter(ControlReportes.Enviado == True)
        
        if filters:
            for filter_condition in filters:
                query = query.filter(filter_condition)
        
        reportes = query.order_by(ControlReportes.Periodo.desc()).all()
        
        # Agrupar por cliente
        clientes_facturacion = {}
        for reporte, cliente in reportes:
            cliente_key = cliente.ID
            
            if cliente_key not in clientes_facturacion:
                clientes_facturacion[cliente_key] = {
                    'cliente': {
                        'id': cliente.ID,
                        'razon_social': cliente.RazonSocial,
                        'nombre_comercial': cliente.NombreComercial,
                        'nit': cliente.NIT,
                        'email': cliente.Email,
                        'telefono': cliente.Telefono,
                        'activo': cliente.Activo
                    },
                    'reportes': [],
                    'total_documentos': 0,
                    'total_valor': 0.0,
                    'periodos_reportados': 0,
                    'tasa_exito_promedio': 0.0
                }
            
            # Agregar reporte
            clientes_facturacion[cliente_key]['reportes'].append({
                'periodo': reporte.Periodo,
                'total_documentos': reporte.TotalDocumentos,
                'documentos_exitosos': reporte.DocumentosExitosos,
                'valor_total': float(reporte.ValorTotal or 0),
                'tasa_exito': float(reporte.TasaExito or 0),
                'fecha_envio': reporte.FechaEnvio.isoformat() if reporte.FechaEnvio else None
            })
            
            # Acumular totales
            clientes_facturacion[cliente_key]['total_documentos'] += reporte.TotalDocumentos or 0
            clientes_facturacion[cliente_key]['total_valor'] += float(reporte.ValorTotal or 0)
            clientes_facturacion[cliente_key]['periodos_reportados'] += 1
        
        # Calcular promedios
        for cliente_data in clientes_facturacion.values():
            if cliente_data['periodos_reportados'] > 0:
                tasa_total = sum(r['tasa_exito'] for r in cliente_data['reportes'])
                cliente_data['tasa_exito_promedio'] = round(tasa_total / cliente_data['periodos_reportados'], 2)
        
        return jsonify({
            'success': True,
            'year': year,
            'month': month,
            'total_clientes': len(clientes_facturacion),
            'clientes_facturacion': list(clientes_facturacion.values())
        })
        
    except Exception as e:
        logger.error(f"Error obteniendo facturación por cliente: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# CLASE MODIFICADA PARA MANEJO DE REPORTES CON CLIENTES
class ReportManager:
    """Maneja la generación y gestión de reportes mensuales por cliente"""
    
    def __init__(self):
        pass
    
    def generate_monthly_report(self, cliente_id: int, target_date: datetime = None) -> Dict[str, Any]:
        """Genera el reporte mensual para un cliente específico"""
        if target_date is None:
            today = datetime.now()
            target_date = datetime(today.year, today.month, 1) - timedelta(days=1)
        
        period = target_date.strftime("%Y-%m")
        start_date = datetime(target_date.year, target_date.month, 1)
        end_date = datetime(target_date.year, target_date.month, calendar.monthrange(target_date.year, target_date.month)[1], 23, 59, 59)
        
        # Obtener información del cliente
        cliente = EmpresaCliente.query.get(cliente_id)
        if not cliente:
            return {
                'success': False,
                'message': f'Cliente con ID {cliente_id} no encontrado',
                'period': period
            }
        
        logger.info(f"Generando reporte para cliente {cliente.RazonSocial} - período {period} ({start_date} - {end_date})")
        
        try:
            # Verificar si ya existe un reporte para este período y cliente
            existing_report = ControlReportes.query.filter_by(Periodo=period, ClienteID=cliente_id, Enviado=True).first()
            if existing_report:
                return {
                    'success': False,
                    'message': f'Ya existe un reporte para el cliente {cliente.RazonSocial} en el período {period}',
                    'period': period
                }
            
            # Obtener estadísticas de facturas electrónicas para este cliente
            invoice_stats = self._get_invoice_statistics_by_client(cliente_id, start_date, end_date)
            
            # Obtener estadísticas de gastos para este cliente
            expense_stats = self._get_expense_statistics_by_client(cliente_id, start_date, end_date)
            
            # Combinar estadísticas
            combined_stats = self._combine_statistics(invoice_stats, expense_stats)
            
            # Generar contenido del reporte
            report_content = self._generate_report_content(
                period, start_date, end_date, cliente, 
                combined_stats, invoice_stats, expense_stats
            )
            
            # Guardar reporte en la base de datos
            report_id = self._save_report(period, cliente_id, combined_stats, report_content, invoice_stats, expense_stats)
            
            logger.info(f"Reporte generado exitosamente para cliente {cliente.RazonSocial} - período {period}")
            
            return {
                'success': True,
                'message': f'Reporte generado exitosamente para {cliente.RazonSocial} - {period}',
                'period': period,
                'cliente': cliente.to_dict(),
                'report_id': report_id,
                'statistics': combined_stats
            }
            
        except Exception as e:
            logger.error(f"Error generando reporte mensual para cliente {cliente_id}: {str(e)}")
            return {
                'success': False,
                'message': f'Error generando reporte: {str(e)}',
                'period': period
            }
    
    def _empty_stats(self) -> Dict[str, Any]:
        """Retorna estadísticas vacías"""
        return {
            'total_documentos': 0,
            'documentos_exitosos': 0,
            'documentos_recibidos': 0,
            'documentos_aceptados': 0,
            'documentos_rechazados': 0,
            'total_subtotal': 0.0,
            'total_iva': 0.0,
            'total_valor': 0.0,
            'tasa_exito': 0.0
        }
    
    def _combine_statistics(self, invoice_stats: Dict[str, Any], expense_stats: Dict[str, Any]) -> Dict[str, Any]:
        """Combina las estadísticas de facturas y gastos"""
        combined = {}
        for key in invoice_stats.keys():
            combined[key] = invoice_stats[key] + expense_stats[key]
        
        # Recalcular tasa de éxito
        total = combined['total_documentos']
        exitosos = combined['documentos_exitosos']
        combined['tasa_exito'] = round((exitosos / total * 100) if total > 0 else 0, 2)
        
        return combined
    
    def _generate_report_content(self, period: str, start_date: datetime, end_date: datetime,
                           cliente: EmpresaCliente, combined_stats: Dict[str, Any],
                           invoice_stats: Dict[str, Any], expense_stats: Dict[str, Any]) -> str:
        """Genera el contenido textual del reporte para un cliente específico"""
        
        month_names = [
            'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
            'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
        ]
        
        month_name = month_names[start_date.month - 1]
        year = start_date.year
        
        content = []
        content.append("REPORTE MENSUAL CONSOLIDADO DE FACTURACIÓN ELECTRÓNICA")
        content.append("=" * 65)
        content.append(f"Fecha de generación: {datetime.now().strftime('%d/%m/%Y %H:%M:%S')}")
        content.append(f"Período analizado: {month_name} {year}")
        content.append("")
        
        # INFORMACIÓN DEL PROVEEDOR (TU EMPRESA)
        content.append("INFORMACIÓN DEL PROVEEDOR:")
        content.append("-" * 30)
        content.append("Razón Social: TransmisionesMig SAS")
        content.append("Nombre Comercial: TransmisionesMig")
        content.append("Servicio: Facturación Electrónica")
        content.append("")
        
        # INFORMACIÓN DEL CLIENTE (LA EMPRESA QUE PAGA)
        content.append("INFORMACIÓN DEL CLIENTE:")
        content.append("-" * 30)
        content.append(f"Razón Social: {cliente.RazonSocial}")
        content.append(f"Nombre Comercial: {cliente.NombreComercial}")
        content.append(f"NIT: {cliente.NIT}")
        if cliente.Email:
            content.append(f"Email: {cliente.Email}")
        if cliente.Telefono:
            content.append(f"Teléfono: {cliente.Telefono}")
        if cliente.Direccion:
            content.append(f"Dirección: {cliente.Direccion}")
        content.append("")
        content.append("=" * 65)
        content.append("")
        
        # RESUMEN EJECUTIVO
        content.append("RESUMEN EJECUTIVO")
        content.append("-" * 20)
        content.append(f"Cliente: {cliente.NombreComercial}")
        content.append(f"Período de facturación: {start_date.strftime('%d/%m/%Y')} - {end_date.strftime('%d/%m/%Y')}")
        if combined_stats['total_documentos'] > 0:
            content.append(f"Total documentos procesados: {combined_stats['total_documentos']:,}")
            content.append(f"Documentos transmitidos exitosamente: {combined_stats['documentos_exitosos']:,}")
            content.append(f"Tasa de éxito: {combined_stats['tasa_exito']:.2f}%")
            content.append(f"Valor total facturado: ${combined_stats['total_valor']:,.2f}")
        else:
            content.append(f"No se encontraron documentos para {cliente.RazonSocial} en este período.")
        content.append("")
        
        # DETALLE TÉCNICO (resto del contenido existente...)
        if combined_stats['total_documentos'] > 0:
            content.append("DETALLE DE FACTURACIÓN ELECTRÓNICA")
            content.append("=" * 40)
            content.append("")
            
            content.append("Estadísticas de Documentos (Facturas y Gastos):")
            content.append(f"- Total Documentos: {combined_stats['total_documentos']:,}")
            content.append(f"- Documentos Transmitidos Exitosamente: {combined_stats['documentos_exitosos']:,}")
            content.append(f"- Documentos NO Transmitidos: {combined_stats['total_documentos'] - combined_stats['documentos_exitosos']:,}")
            content.append("")
            content.append("Indicadores de Efectividad:")
            content.append(f"- Tasa de Transmisión Exitosa: {combined_stats['tasa_exito']:.2f}%")
            content.append(f"- Tasa de Fallos en Transmisión: {100 - combined_stats['tasa_exito']:.2f}%")
            content.append("")
            content.append("Resumen Financiero:")
            content.append(f"- Subtotal: ${combined_stats['total_subtotal']:,.2f}")
            content.append(f"- IVA: ${combined_stats['total_iva']:,.2f}")
            content.append(f"- Total: ${combined_stats['total_valor']:,.2f}")
            content.append("")
            
            # Detalle separado por tipo de documento
            content.append("DETALLE POR TIPO DE DOCUMENTO")
            content.append("=" * 35)
            content.append("")
            
            # Detalle de Facturas
            if invoice_stats['total_documentos'] > 0:
                tasa_exito_facturas = (invoice_stats['documentos_exitosos'] / invoice_stats['total_documentos'] * 100) if invoice_stats['total_documentos'] > 0 else 0
                content.append("Facturas Electrónicas:")
                content.append(f"- Total Documentos: {invoice_stats['total_documentos']:,}")
                content.append(f"- Transmitidos Exitosamente: {invoice_stats['documentos_exitosos']:,} ({tasa_exito_facturas:.2f}%)")
                content.append(f"- NO Transmitidos: {invoice_stats['total_documentos'] - invoice_stats['documentos_exitosos']:,} ({(100 - tasa_exito_facturas):.2f}%)")
                content.append(f"- Valor Total: ${invoice_stats['total_valor']:,.2f}")
                content.append("")
            
            # Detalle de Gastos
            if expense_stats['total_documentos'] > 0:
                tasa_exito_gastos = (expense_stats['documentos_exitosos'] / expense_stats['total_documentos'] * 100) if expense_stats['total_documentos'] > 0 else 0
                content.append("Documentos de Gastos:")
                content.append(f"- Total Documentos: {expense_stats['total_documentos']:,}")
                content.append(f"- Transmitidos Exitosamente: {expense_stats['documentos_exitosos']:,} ({tasa_exito_gastos:.2f}%)")
                content.append(f"- NO Transmitidos: {expense_stats['total_documentos'] - expense_stats['documentos_exitosos']:,} ({(100 - tasa_exito_gastos):.2f}%)")
                content.append(f"- Valor Total: ${expense_stats['total_valor']:,.2f}")
                content.append("")
        
        content.append("=" * 65)
        content.append("NOTA IMPORTANTE:")
        content.append("Este reporte incluye documentos de las tablas fe_documentos y Gastos1")
        content.append("procesados durante el período indicado.")
        content.append("Solo se evalúa el estado de transmisión (transmitido/no transmitido) para ambas tablas.")
        content.append("")
        content.append("Para cualquier consulta sobre este reporte, contacte a:")
        content.append("TransmisionesMig SAS - Servicios de Facturación Electrónica")
        content.append("=" * 65)
        
        return "\n".join(content)
    
    def _save_report(self, period: str, cliente_id: int, combined_stats: Dict[str, Any], content: str,
                    invoice_stats: Dict[str, Any], expense_stats: Dict[str, Any]) -> int:
        """Guarda el reporte en la base de datos con información del cliente"""
        try:
            report = ControlReportes(
                Periodo=period,
                ClienteID=cliente_id,
                FechaEnvio=datetime.utcnow(),
                Enviado=True,
                Observaciones='Reporte generado automáticamente',
                TotalDocumentos=combined_stats['total_documentos'],
                DocumentosExitosos=combined_stats['documentos_exitosos'],
                ValorTotal=combined_stats['total_valor'],
                TasaExito=combined_stats['tasa_exito'],
                ContenidoCompleto=content,
                DetalleFacturas=json.dumps(invoice_stats),
                DetalleGastos=json.dumps(expense_stats)
            )
            
            db.session.add(report)
            db.session.commit()
            
            return report.ID
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"Error guardando reporte: {str(e)}")
            raise
    
    def get_all_reports(self) -> List[Dict[str, Any]]:
        """Obtiene todos los reportes con información del cliente"""
        try:
            reports = ControlReportes.query.order_by(ControlReportes.Periodo.desc()).all()
            return [report.to_dict() for report in reports]
        except Exception as e:
            logger.error(f"Error obteniendo reportes: {str(e)}")
            return []
    
    def get_report_detail(self, report_id: int) -> Optional[Dict[str, Any]]:
        """Obtiene el detalle completo de un reporte"""
        try:
            report = ControlReportes.query.get(report_id)
            return report.to_dict() if report else None
        except Exception as e:
            logger.error(f"Error obteniendo detalle del reporte {report_id}: {str(e)}")
            return None
    
    def get_reports_by_client(self, cliente_id: int) -> List[Dict[str, Any]]:
        """Obtiene todos los reportes de un cliente específico"""
        try:
            reports = ControlReportes.query.filter_by(ClienteID=cliente_id).order_by(ControlReportes.Periodo.desc()).all()
            return [report.to_dict() for report in reports]
        except Exception as e:
            logger.error(f"Error obteniendo reportes del cliente {cliente_id}: {str(e)}")
            return []

# FUNCIÓN PARA CREAR TABLAS Y DATOS INICIALES
def crear_tablas():
    """Crear todas las tablas automáticamente"""
    try:
        # Crear todas las tablas
        db.create_all()
        logger.info("✓ Tablas creadas/verificadas exitosamente")
            
        db.session.commit()
        logger.info("✓ Clientes de ejemplo creados")
        
    except Exception as e:
        logger.error(f"✗ Error creando tablas: {e}")
        db.session.rollback()
        return False

# Inicializar el report manager
report_manager = ReportManager()

# RUTAS DE LA APLICACIÓN

@app.route('/')
def index():
    """Página principal"""
    try:
        return render_template('index.html')
    except Exception as e:
        logger.error(f"Error cargando página principal: {str(e)}")
        return f"Error cargando la aplicación: {str(e)}", 500

@app.route('/static/<path:filename>')
def static_files(filename):
    """Servir archivos estáticos"""
    try:
        return send_from_directory('/var/www/html/TransmisionesMig/static', filename)
    except Exception as e:
        logger.error(f"Error sirviendo archivo estático {filename}: {str(e)}")
        return "Archivo no encontrado", 404

@app.route('/test')
def test():
    """Endpoint de prueba"""
    return jsonify({
        'status': 'ok',
        'message': 'Servidor funcionando correctamente',
        'timestamp': datetime.now().isoformat()
    })

@app.route('/test-db')
def test_db():
    """Probar conexión a base de datos"""
    try:
        db.session.execute(text('SELECT 1'))
        clientes_count = EmpresaCliente.query.count()
        reportes_count = ControlReportes.query.count()
        return jsonify({
            'status': 'ok',
            'message': 'Base de datos conectada',
            'clientes_count': clientes_count,
            'reportes_count': reportes_count,
            'db_uri': app.config['SQLALCHEMY_DATABASE_URI'].split('@')[1]
        })
    except Exception as e:
        logger.error(f"Error en test-db: {str(e)}")
        return jsonify({
            'status': 'error',
            'message': str(e)
        }), 500

@app.route('/init-db')
def init_database():
    """Inicializar 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:
        logger.error(f"Error en init-db: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# RUTAS PARA GESTIÓN DE CLIENTES

@app.route('/api/clientes', methods=['GET'])
def get_clientes():
    """Obtiene la lista de clientes"""
    try:
        clientes = EmpresaCliente.query.filter_by(Activo=True).order_by(EmpresaCliente.RazonSocial).all()
        return jsonify([cliente.to_dict() for cliente in clientes])
    except Exception as e:
        logger.error(f"Error obteniendo clientes: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/clientes', methods=['POST'])
def create_cliente():
    """Crea un nuevo cliente"""
    try:
        data = request.get_json()
        
        # Validar campos obligatorios
        required_fields = ['razon_social', 'nombre_comercial', 'nit']
        for field in required_fields:
            if not data.get(field):
                return jsonify({
                    'success': False,
                    'error': f'El campo {field} es obligatorio'
                }), 400
        
        # Verificar si ya existe un cliente con ese NIT
        existing = EmpresaCliente.query.filter_by(NIT=data['nit']).first()
        if existing:
            return jsonify({
                'success': False,
                'error': f'Ya existe un cliente con NIT {data["nit"]}'
            }), 400
        
        # Crear nuevo cliente
        cliente = EmpresaCliente(
            RazonSocial=data['razon_social'],
            NombreComercial=data['nombre_comercial'],
            NIT=data['nit'],
            Email=data.get('email', ''),
            Telefono=data.get('telefono', ''),
            Direccion=data.get('direccion', ''),
            Activo=data.get('activo', True)
        )
        
        db.session.add(cliente)
        db.session.commit()
        
        logger.info(f"Cliente creado: {cliente.RazonSocial} (NIT: {cliente.NIT})")
        
        return jsonify({
            'success': True,
            'message': 'Cliente creado exitosamente',
            'cliente': cliente.to_dict()
        }), 201
        
    except Exception as e:
        logger.error(f"Error creando cliente: {str(e)}")
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/clientes/<int:cliente_id>', methods=['PUT'])
def update_cliente(cliente_id):
    """Actualiza un cliente"""
    try:
        cliente = EmpresaCliente.query.get(cliente_id)
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'Cliente no encontrado'
            }), 404
        
        data = request.get_json()
        
        # Actualizar campos
        if 'razon_social' in data:
            cliente.RazonSocial = data['razon_social']
        if 'nombre_comercial' in data:
            cliente.NombreComercial = data['nombre_comercial']
        if 'email' in data:
            cliente.Email = data['email']
        if 'telefono' in data:
            cliente.Telefono = data['telefono']
        if 'direccion' in data:
            cliente.Direccion = data['direccion']
        if 'activo' in data:
            cliente.Activo = data['activo']
        
        cliente.FechaModificacion = datetime.utcnow()
        
        db.session.commit()
        
        logger.info(f"Cliente actualizado: {cliente.RazonSocial} (ID: {cliente.ID})")
        
        return jsonify({
            'success': True,
            'message': 'Cliente actualizado exitosamente',
            'cliente': cliente.to_dict()
        })
        
    except Exception as e:
        logger.error(f"Error actualizando cliente {cliente_id}: {str(e)}")
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/clientes/<int:cliente_id>', methods=['DELETE'])
def delete_cliente(cliente_id):
    """Desactiva un cliente (soft delete)"""
    try:
        cliente = EmpresaCliente.query.get(cliente_id)
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'Cliente no encontrado'
            }), 404
        
        # Verificar si tiene reportes asociados
        reportes_count = ControlReportes.query.filter_by(ClienteID=cliente_id).count()
        
        if reportes_count > 0:
            # Soft delete: solo desactivar
            cliente.Activo = False
            cliente.FechaModificacion = datetime.utcnow()
            db.session.commit()
            
            message = f'Cliente {cliente.RazonSocial} desactivado (tiene {reportes_count} reportes asociados)'
        else:
            # Hard delete: eliminar completamente
            razon_social = cliente.RazonSocial
            db.session.delete(cliente)
            db.session.commit()
            
            message = f'Cliente {razon_social} eliminado completamente'
        
        logger.info(f"Cliente eliminado/desactivado: {cliente.RazonSocial} (ID: {cliente_id})")
        
        return jsonify({
            'success': True,
            'message': message
        })
        
    except Exception as e:
        logger.error(f"Error eliminando cliente {cliente_id}: {str(e)}")
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/clientes/<int:cliente_id>/reportes', methods=['GET'])
def get_reportes_by_cliente(cliente_id):
    """Obtiene todos los reportes de un cliente específico"""
    try:
        cliente = EmpresaCliente.query.get(cliente_id)
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'Cliente no encontrado'
            }), 404
        
        reportes = report_manager.get_reports_by_client(cliente_id)
        
        return jsonify({
            'success': True,
            'cliente': cliente.to_dict(),
            'reportes': reportes
        })
        
    except Exception as e:
        logger.error(f"Error obteniendo reportes del cliente {cliente_id}: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    
@app.route('/api/test-pos-connection', methods=['GET'])
def test_pos_connection():
    """Endpoint para que el POS pruebe la conectividad"""
    try:
        return jsonify({
            'status': 'ok',
            'message': 'Conexión desde POS exitosa',
            'timestamp': datetime.now().isoformat(),
            'server': 'Reportes Web MIG',
            'version': '1.0',
            'cliente_sistema': 'TransmisionesMig POS'
        })
    except Exception as e:
        logger.error(f"Error en test-pos-connection: {str(e)}")
        return jsonify({
            'status': 'error',
            'message': str(e)
        }), 500

@app.route('/api/reportes-desde-pos', methods=['POST'])
def recibir_reporte_desde_pos():
    """Recibe reportes enviados desde el sistema POS"""
    try:
        data = request.get_json()
        
        logger.info(f"📥 Recibiendo reporte desde POS - Período: {data.get('periodo')}")
        
        # Validar datos requeridos
        required_fields = ['periodo', 'fecha_envio', 'empresa']
        for field in required_fields:
            if not data.get(field):
                return jsonify({
                    'success': False,
                    'error': f'Campo requerido faltante: {field}'
                }), 400
        
        # Verificar o crear cliente basado en NIT
        empresa_data = data['empresa']
        cliente = verificar_o_crear_cliente_desde_pos(empresa_data)
        
        if not cliente:
            return jsonify({
                'success': False,
                'error': 'No se pudo crear/verificar el cliente'
            }), 400
        
        # Verificar si ya existe un reporte para este período y cliente
        period = data['periodo']
        existing_report = ControlReportes.query.filter_by(
            Periodo=period, 
            ClienteID=cliente.ID, 
            Enviado=True
        ).first()
        
        if existing_report:
            # Actualizar reporte existente si viene del POS
            actualizar_reporte_existente(existing_report, data)
            mensaje = f'Reporte {period} actualizado para {cliente.RazonSocial}'
        else:
            # Crear nuevo reporte
            report_id = crear_reporte_desde_pos(cliente.ID, data)
            mensaje = f'Reporte {period} creado para {cliente.RazonSocial}'
        
        logger.info(f"✅ {mensaje}")
        
        return jsonify({
            'success': True,
            'message': mensaje,
            'cliente': {
                'id': cliente.ID,
                'razon_social': cliente.RazonSocial,
                'nombre_comercial': cliente.NombreComercial,
                'nit': cliente.NIT
            },
            'periodo': period
        })
        
    except Exception as e:
        logger.error(f"❌ Error recibiendo reporte desde POS: {str(e)}")
        return jsonify({
            'success': False,
            'error': f'Error interno: {str(e)}'
        }), 500

def verificar_o_crear_cliente_desde_pos(empresa_data):
    """Verifica si existe un cliente o lo crea basado en datos del POS"""
    try:
        nit = empresa_data.get('nit', '').strip()
        
        if not nit:
            logger.warning("⚠️ NIT vacío en datos desde POS")
            return None
        
        # Buscar cliente existente por NIT
        cliente = EmpresaCliente.query.filter_by(NIT=nit).first()
        
        if cliente:
            # Actualizar información si es necesaria
            cliente_actualizado = False
            
            if empresa_data.get('razon_social') and cliente.RazonSocial != empresa_data['razon_social']:
                cliente.RazonSocial = empresa_data['razon_social']
                cliente_actualizado = True
            
            if empresa_data.get('nombre_comercial') and cliente.NombreComercial != empresa_data['nombre_comercial']:
                cliente.NombreComercial = empresa_data['nombre_comercial']
                cliente_actualizado = True
            
            if empresa_data.get('email') and cliente.Email != empresa_data['email']:
                cliente.Email = empresa_data['email']
                cliente_actualizado = True
            
            if empresa_data.get('telefono') and cliente.Telefono != empresa_data['telefono']:
                cliente.Telefono = empresa_data['telefono']
                cliente_actualizado = True
            
            if cliente_actualizado:
                cliente.FechaModificacion = datetime.utcnow()
                db.session.commit()
                logger.info(f"Cliente actualizado: {cliente.RazonSocial}")
            
            return cliente
        else:
            # Crear nuevo cliente
            nuevo_cliente = EmpresaCliente(
                RazonSocial=empresa_data.get('razon_social', 'Sin Definir'),
                NombreComercial=empresa_data.get('nombre_comercial', 'Sin Definir'),
                NIT=nit,
                Email=empresa_data.get('email', ''),
                Telefono=empresa_data.get('telefono', ''),
                Direccion='',
                Activo=True
            )
            
            db.session.add(nuevo_cliente)
            db.session.commit()
            
            logger.info(f"Nuevo cliente creado desde POS: {nuevo_cliente.RazonSocial} (NIT: {nit})")
            return nuevo_cliente
            
    except Exception as e:
        logger.error(f"Error verificando/creando cliente desde POS: {str(e)}")
        db.session.rollback()
        return None

def actualizar_reporte_existente(reporte, data):
    """Actualiza un reporte existente con datos del POS"""
    try:
        # Actualizar campos del reporte
        if data.get('total_documentos'):
            reporte.TotalDocumentos = data['total_documentos']
        if data.get('documentos_exitosos'):
            reporte.DocumentosExitosos = data['documentos_exitosos']
        if data.get('valor_total'):
            reporte.ValorTotal = data['valor_total']
        if data.get('tasa_exito'):
            reporte.TasaExito = data['tasa_exito']
        if data.get('contenido_completo'):
            reporte.ContenidoCompleto = data['contenido_completo']
        
        # Actualizar observaciones
        reporte.Observaciones = f"Actualizado desde POS - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
        reporte.FechaEnvio = datetime.utcnow()
        
        db.session.commit()
        
    except Exception as e:
        logger.error(f"Error actualizando reporte existente: {str(e)}")
        db.session.rollback()

def crear_reporte_desde_pos(cliente_id, data):
    """Crea un nuevo reporte desde datos del POS"""
    try:
        nuevo_reporte = ControlReportes(
            Periodo=data['periodo'],
            ClienteID=cliente_id,
            FechaEnvio=datetime.utcnow(),
            Enviado=True,
            Observaciones=f"Creado desde POS - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
            TotalDocumentos=data.get('total_documentos', 0),
            DocumentosExitosos=data.get('documentos_exitosos', 0),
            ValorTotal=data.get('valor_total', 0),
            TasaExito=data.get('tasa_exito', 0),
            ContenidoCompleto=data.get('contenido_completo', ''),
            DetalleFacturas=json.dumps(data.get('detalle_facturas', {})),
            DetalleGastos=json.dumps(data.get('detalle_gastos', {}))
        )
        
        db.session.add(nuevo_reporte)
        db.session.commit()
        
        return nuevo_reporte.ID
        
    except Exception as e:
        logger.error(f"Error creando reporte desde POS: {str(e)}")
        db.session.rollback()
        return None

# RUTAS MODIFICADAS PARA REPORTES CON CLIENTES

@app.route('/api/status', methods=['GET'])
def get_status():
    """Obtiene el estado del sistema con información de clientes"""
    try:
        # Probar conexión a la base de datos
        try:
            db.session.execute(text('SELECT 1'))
            db_connected = True
        except:
            db_connected = False
        
        # Obtener información del último reporte
        last_report = None
        if db_connected:
            try:
                ultimo = ControlReportes.query.order_by(ControlReportes.FechaEnvio.desc()).first()
                if ultimo:
                    last_report = {
                        'periodo': ultimo.Periodo,
                        'fecha_envio': ultimo.FechaEnvio.isoformat(),
                        'cliente': ultimo.empresa_cliente.to_dict() if ultimo.empresa_cliente else None
                    }
            except Exception as e:
                logger.warning(f"Error obteniendo último reporte: {str(e)}")
        
        # Estadísticas generales
        clientes_activos = EmpresaCliente.query.filter_by(Activo=True).count() if db_connected else 0
        total_reportes = ControlReportes.query.count() if db_connected else 0
        
        # Calcular próxima fecha de reporte
        now = datetime.now()
        next_month = datetime(now.year, now.month + 1, 1) if now.month < 12 else datetime(now.year + 1, 1, 1)
        next_report_date = datetime(next_month.year, next_month.month, 5)
        
        return jsonify({
            'db_connected': db_connected,
            'last_report': last_report,
            'next_report_date': next_report_date.isoformat(),
            'current_time': datetime.now().isoformat(),
            'clientes_activos': clientes_activos,
            'total_reportes': total_reportes
        })
        
    except Exception as e:
        logger.error(f"Error obteniendo estado: {str(e)}")
        return jsonify({
            'db_connected': False,
            'error': str(e),
            'current_time': datetime.now().isoformat()
        }), 500

@app.route('/api/reports', methods=['GET'])
def get_reports():
    """Obtiene la lista de reportes con información de clientes"""
    try:
        # Permitir filtrar por cliente
        cliente_id = request.args.get('cliente_id')
        
        if cliente_id:
            reports = report_manager.get_reports_by_client(int(cliente_id))
        else:
            reports = report_manager.get_all_reports()
        
        return jsonify(reports)
    except Exception as e:
        logger.error(f"Error obteniendo reportes: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/reports/<int:report_id>', methods=['GET'])
def get_report_detail(report_id):
    """Obtiene el detalle de un reporte específico"""
    try:
        report = report_manager.get_report_detail(report_id)
        if report:
            return jsonify(report)
        else:
            return jsonify({'error': 'Reporte no encontrado'}), 404
    except Exception as e:
        logger.error(f"Error obteniendo detalle del reporte {report_id}: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/generate-report', methods=['POST'])
def generate_report():
    """Genera un nuevo reporte mensual para un cliente específico"""
    try:
        data = request.get_json() or {}
        
        # Cliente es obligatorio
        cliente_id = data.get('cliente_id')
        if not cliente_id:
            return jsonify({
                'success': False,
                'message': 'El cliente_id es obligatorio'
            }), 400
        
        target_date = None
        if 'year' in data and 'month' in data:
            target_date = datetime(int(data['year']), int(data['month']), 1)
        
        result = report_manager.generate_monthly_report(cliente_id, target_date)
        
        if result['success']:
            return jsonify(result)
        else:
            return jsonify(result), 400
            
    except Exception as e:
        logger.error(f"Error generando reporte: {str(e)}")
        return jsonify({
            'success': False,
            'message': f'Error interno del servidor: {str(e)}'
        }), 500

@app.route('/api/generate-all-reports', methods=['POST'])
def generate_all_reports():
    """Genera reportes para todos los clientes activos"""
    try:
        data = request.get_json() or {}
        
        target_date = None
        if 'year' in data and 'month' in data:
            target_date = datetime(int(data['year']), int(data['month']), 1)
        
        # Obtener todos los clientes activos
        clientes = EmpresaCliente.query.filter_by(Activo=True).all()
        
        results = []
        generated_count = 0
        
        for cliente in clientes:
            result = report_manager.generate_monthly_report(cliente.ID, target_date)
            results.append({
                'cliente': cliente.to_dict(),
                'result': result
            })
            
            if result['success']:
                generated_count += 1
        
        return jsonify({
            'success': True,
            'message': f'Se generaron {generated_count} reportes de {len(clientes)} clientes',
            'generated_count': generated_count,
            'total_clients': len(clientes),
            'results': results
        })
            
    except Exception as e:
        logger.error(f"Error generando reportes para todos los clientes: {str(e)}")
        return jsonify({
            'success': False,
            'message': f'Error interno del servidor: {str(e)}'
        }), 500

@app.route('/api/verify-missing', methods=['POST'])
def verify_missing():
    """Verifica y genera reportes faltantes para todos los clientes"""
    try:
        # Obtener todos los clientes activos
        clientes = EmpresaCliente.query.filter_by(Activo=True).all()
        
        current_date = datetime.now()
        current_year = current_date.year
        current_month = current_date.month
        previous_year = current_year - 1
        
        total_generated = 0
        results_by_client = []
        
        for cliente in clientes:
            generated_count = 0
            generated_periods = []
            
            # Verificar año anterior completo (12 meses)
            for month in range(1, 13):
                period = f"{previous_year}-{month:02d}"
                existing = ControlReportes.query.filter_by(Periodo=period, ClienteID=cliente.ID, Enviado=True).first()
                if not existing:
                    target_date = datetime(previous_year, month, calendar.monthrange(previous_year, month)[1])
                    result = report_manager.generate_monthly_report(cliente.ID, target_date)
                    if result['success']:
                        generated_count += 1
                        generated_periods.append(period)
            
            # Verificar año actual hasta el mes anterior
            for month in range(1, current_month):
                period = f"{current_year}-{month:02d}"
                existing = ControlReportes.query.filter_by(Periodo=period, ClienteID=cliente.ID, Enviado=True).first()
                if not existing:
                    target_date = datetime(current_year, month, calendar.monthrange(current_year, month)[1])
                    result = report_manager.generate_monthly_report(cliente.ID, target_date)
                    if result['success']:
                        generated_count += 1
                        generated_periods.append(period)
            
            total_generated += generated_count
            
            results_by_client.append({
                'cliente': cliente.to_dict(),
                'generated_count': generated_count,
                'generated_periods': generated_periods
            })
        
        logger.info(f"Verificación completada. Se generaron {total_generated} reportes faltantes para {len(clientes)} clientes.")
        
        return jsonify({
            'success': True,
            'generated_count': total_generated,
            'total_clients': len(clientes),
            'message': f'Se generaron {total_generated} reportes faltantes para {len(clientes)} clientes',
            'results_by_client': results_by_client
        })
        
    except Exception as e:
        logger.error(f"Error verificando reportes faltantes: {str(e)}")
        return jsonify({
            'success': False,
            'generated_count': 0,
            'message': f'Error interno del servidor: {str(e)}'
        }), 500

@app.route('/api/reports/<int:report_id>/download', methods=['GET'])
def download_report(report_id):
    """Descarga un reporte en formato texto"""
    try:
        report = report_manager.get_report_detail(report_id)
        if not report:
            return jsonify({'error': 'Reporte no encontrado'}), 404
        
        content = report.get('contenido_completo', '')
        if not content:
            return jsonify({'error': 'Contenido del reporte no disponible'}), 404
        
        # Crear archivo en memoria
        bytes_buffer = io.BytesIO()
        bytes_buffer.write(content.encode('utf-8'))
        bytes_buffer.seek(0)
        
        # Nombre del archivo incluye información del cliente
        cliente_info = report.get('cliente', {})
        cliente_name = cliente_info.get('nombre_comercial', 'Cliente').replace(' ', '_')
        filename = f"Reporte_{cliente_name}_{report['periodo']}.txt"
        
        return send_file(
            bytes_buffer,
            as_attachment=True,
            download_name=filename,
            mimetype='text/plain'
        )
        
    except Exception as e:
        logger.error(f"Error descargando reporte {report_id}: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/reports/export', methods=['GET'])
def export_reports():
    """Exporta todos los reportes a Excel con información de clientes - ORDENADO ALFABÉTICAMENTE"""
    try:
        reports = report_manager.get_all_reports()
        
        if not reports:
            return jsonify({'error': 'No hay reportes para exportar'}), 404
        
        # Preparar datos para Excel con manejo de valores None
        excel_data = []
        for report in reports:
            try:
                cliente = report.get('cliente') or {}
                
                excel_data.append({
                    'Razón Social': cliente.get('razon_social', 'N/A'),
                    'Nombre Comercial': cliente.get('nombre_comercial', 'N/A'),
                    'NIT': cliente.get('nit', 'N/A'),
                    'Período': report.get('periodo', 'N/A'),
                    'Total Documentos': report.get('total_documentos', 0),
                    'Documentos Exitosos': report.get('documentos_exitosos', 0),
                    'Tasa de Éxito (%)': report.get('tasa_exito', 0),
                    'Valor Total': report.get('valor_total', 0),
                    'Fecha Generación': report.get('fecha_envio', 'N/A'),
                    'Estado': 'Completado' if report.get('status') == 'completed' else 'Pendiente',
                    'Email': cliente.get('email', ''),
                    'Teléfono': cliente.get('telefono', ''),
                    'Activo': 'Sí' if cliente.get('activo') else 'No',
                    'Observaciones': report.get('observaciones') or ''
                })
            except Exception as e:
                logger.error(f"Error procesando reporte {report.get('id')}: {str(e)}")
                continue
        
        if not excel_data:
            return jsonify({'error': 'No se pudieron procesar los reportes'}), 500
        
        # Crear DataFrame
        df = pd.DataFrame(excel_data)
        
        # *** ORDENAR ALFABÉTICAMENTE POR RAZÓN SOCIAL ***
        df = df.sort_values(by='Razón Social', ascending=True, na_position='last')
        
        # Formatear fechas de manera segura
        if 'Fecha Generación' in df.columns:
            try:
                df['Fecha Generación'] = pd.to_datetime(df['Fecha Generación'], errors='coerce').dt.strftime('%Y-%m-%d %H:%M:%S')
            except Exception as e:
                logger.warning(f"Error formateando fechas: {str(e)}")
        
        # Crear archivo Excel en memoria
        excel_buffer = io.BytesIO()
        
        try:
            with pd.ExcelWriter(excel_buffer, engine='openpyxl') as writer:
                df.to_excel(writer, sheet_name='Reportes por Cliente', index=False)
                
                # Ajustar ancho de columnas
                worksheet = writer.sheets['Reportes por Cliente']
                for idx, col in enumerate(df.columns):
                    max_length = max(
                        df[col].astype(str).apply(len).max(),
                        len(col)
                    ) + 2
                    worksheet.column_dimensions[chr(65 + idx)].width = min(max_length, 50)
        except Exception as e:
            logger.error(f"Error creando Excel: {str(e)}")
            return jsonify({'error': f'Error al crear archivo Excel: {str(e)}'}), 500
        
        excel_buffer.seek(0)
        
        filename = f"Reportes_Clientes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        
        return send_file(
            excel_buffer,
            as_attachment=True,
            download_name=filename,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
        
    except Exception as e:
        logger.error(f"Error exportando reportes: {str(e)}")
        import traceback
        logger.error(traceback.format_exc())
        return jsonify({'error': f'Error interno al exportar: {str(e)}'}), 500

@app.route('/api/actualizar-estado-facturacion', methods=['POST'])
def actualizar_estado_facturacion():
    """Actualiza el estado de facturación de un reporte desde el POS"""
    try:
        data = request.get_json()
        
        logger.info(f"📋 Actualizando estado de facturación - Período: {data.get('periodo')}")
        
        # Validar datos requeridos
        required_fields = ['periodo', 'numero_factura', 'cliente_nit', 'fecha_facturacion']
        for field in required_fields:
            if not data.get(field):
                return jsonify({
                    'success': False,
                    'error': f'Campo requerido faltante: {field}'
                }), 400
        
        periodo = data['periodo']
        numero_factura = data['numero_factura']
        cliente_nit = data['cliente_nit']
        fecha_facturacion_str = data['fecha_facturacion']
        
        # Convertir fecha
        try:
            fecha_facturacion = datetime.fromisoformat(fecha_facturacion_str.replace('T', ' '))
        except:
            fecha_facturacion = datetime.now()
        
        # Buscar el cliente por NIT
        cliente = EmpresaCliente.query.filter_by(NIT=cliente_nit).first()
        if not cliente:
            return jsonify({
                'success': False,
                'error': f'Cliente con NIT {cliente_nit} no encontrado'
            }), 404
        
        # Buscar el reporte específico
        reporte = ControlReportes.query.filter_by(
            Periodo=periodo,
            ClienteID=cliente.ID,
            Enviado=True
        ).first()
        
        if not reporte:
            return jsonify({
                'success': False,
                'error': f'Reporte para período {periodo} y cliente {cliente.RazonSocial} no encontrado'
            }), 404
        
        # Actualizar estado de facturación
        reporte.Facturado = True
        reporte.FechaFacturacion = fecha_facturacion
        reporte.NumeroFactura = numero_factura
        
        # Actualizar observaciones
        observaciones_facturacion = f"Facturado desde POS - Factura #{numero_factura} - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
        if reporte.Observaciones:
            reporte.Observaciones += f" | {observaciones_facturacion}"
        else:
            reporte.Observaciones = observaciones_facturacion
        
        db.session.commit()
        
        logger.info(f"✅ Estado de facturación actualizado - Cliente: {cliente.RazonSocial}, Período: {periodo}, Factura: {numero_factura}")
        
        return jsonify({
            'success': True,
            'message': f'Estado de facturación actualizado exitosamente',
            'cliente': {
                'id': cliente.ID,
                'razon_social': cliente.RazonSocial,
                'nombre_comercial': cliente.NombreComercial,
                'nit': cliente.NIT
            },
            'reporte': {
                'id': reporte.ID,
                'periodo': reporte.Periodo,
                'facturado': reporte.Facturado,
                'numero_factura': reporte.NumeroFactura,
                'fecha_facturacion': reporte.FechaFacturacion.isoformat() if reporte.FechaFacturacion else None
            }
        })
        
    except Exception as e:
        logger.error(f"❌ Error actualizando estado de facturación: {str(e)}")
        db.session.rollback()
        return jsonify({
            'success': False,
            'error': f'Error interno: {str(e)}'
        }), 500

@app.route('/api/reportes-pendientes-facturacion', methods=['GET'])
def get_reportes_pendientes_facturacion():
    """Obtiene reportes que están pendientes de facturación"""
    try:
        # Filtros opcionales
        year = request.args.get('year')
        month = request.args.get('month')
        cliente_id = request.args.get('cliente_id')
        
        # Consulta base: reportes enviados pero no facturados
        query = db.session.query(ControlReportes, EmpresaCliente).join(
            EmpresaCliente, ControlReportes.ClienteID == EmpresaCliente.ID
        ).filter(
            ControlReportes.Enviado == True,
            ControlReportes.Facturado == False  # Solo los no facturados
        )
        
        # Aplicar filtros
        if year:
            if month:
                period_filter = f"{year}-{str(month).zfill(2)}"
                query = query.filter(ControlReportes.Periodo == period_filter)
            else:
                query = query.filter(ControlReportes.Periodo.like(f"{year}-%"))
        
        if cliente_id:
            query = query.filter(ControlReportes.ClienteID == cliente_id)
        
        reportes_pendientes = query.order_by(ControlReportes.Periodo.desc()).all()
        
        # Formatear respuesta
        resultado = []
        for reporte, cliente in reportes_pendientes:
            resultado.append({
                'reporte_id': reporte.ID,
                'periodo': reporte.Periodo,
                'cliente_nit': cliente.NIT,
                'cliente_razon_social': cliente.RazonSocial,
                'cliente_nombre_comercial': cliente.NombreComercial,
                'valor_total': float(reporte.ValorTotal or 0),
                'total_documentos': reporte.TotalDocumentos or 0,
                'documentos_exitosos': reporte.DocumentosExitosos or 0,
                'fecha_envio': reporte.FechaEnvio.isoformat() if reporte.FechaEnvio else None,
                'facturado': reporte.Facturado or False
            })
        
        logger.info(f"📋 Obtenidos {len(resultado)} reportes pendientes de facturación")
        
        return jsonify(resultado)
        
    except Exception as e:
        logger.error(f"❌ Error obteniendo reportes pendientes: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/reportes-facturados', methods=['GET'])
def get_reportes_facturados():
    """Obtiene reportes que ya han sido facturados"""
    try:
        # Filtros opcionales
        year = request.args.get('year')
        month = request.args.get('month')
        cliente_id = request.args.get('cliente_id')
        
        # Consulta base: reportes facturados
        query = db.session.query(ControlReportes, EmpresaCliente).join(
            EmpresaCliente, ControlReportes.ClienteID == EmpresaCliente.ID
        ).filter(
            ControlReportes.Enviado == True,
            ControlReportes.Facturado == True  # Solo los facturados
        )
        
        # Aplicar filtros
        if year:
            if month:
                period_filter = f"{year}-{str(month).zfill(2)}"
                query = query.filter(ControlReportes.Periodo == period_filter)
            else:
                query = query.filter(ControlReportes.Periodo.like(f"{year}-%"))
        
        if cliente_id:
            query = query.filter(ControlReportes.ClienteID == cliente_id)
        
        reportes_facturados = query.order_by(ControlReportes.FechaFacturacion.desc()).all()
        
        # Formatear respuesta
        resultado = []
        for reporte, cliente in reportes_facturados:
            resultado.append({
                'reporte_id': reporte.ID,
                'periodo': reporte.Periodo,
                'cliente_nit': cliente.NIT,
                'cliente_razon_social': cliente.RazonSocial,
                'cliente_nombre_comercial': cliente.NombreComercial,
                'valor_total': float(reporte.ValorTotal or 0),
                'total_documentos': reporte.TotalDocumentos or 0,
                'documentos_exitosos': reporte.DocumentosExitosos or 0,
                'fecha_envio': reporte.FechaEnvio.isoformat() if reporte.FechaEnvio else None,
                'facturado': reporte.Facturado,
                'numero_factura': reporte.NumeroFactura,
                'fecha_facturacion': reporte.FechaFacturacion.isoformat() if reporte.FechaFacturacion else None
            })
        
        logger.info(f"💰 Obtenidos {len(resultado)} reportes facturados")
        
        return jsonify(resultado)
        
    except Exception as e:
        logger.error(f"❌ Error obteniendo reportes facturados: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/estadisticas-facturacion', methods=['GET'])
def get_estadisticas_facturacion():
    """Obtiene estadísticas generales de facturación"""
    try:
        year = request.args.get('year', datetime.now().year)
        
        # Consultar reportes del año
        reportes_query = ControlReportes.query.filter(
            ControlReportes.Periodo.like(f"{year}-%"),
            ControlReportes.Enviado == True
        )
        
        total_reportes = reportes_query.count()
        reportes_facturados = reportes_query.filter(ControlReportes.Facturado == True).count()
        reportes_pendientes = total_reportes - reportes_facturados
        
        # Calcular valores
        valor_total_facturado = db.session.query(
            db.func.sum(ControlReportes.ValorTotal)
        ).filter(
            ControlReportes.Periodo.like(f"{year}-%"),
            ControlReportes.Enviado == True,
            ControlReportes.Facturado == True
        ).scalar() or 0
        
        valor_total_pendiente = db.session.query(
            db.func.sum(ControlReportes.ValorTotal)
        ).filter(
            ControlReportes.Periodo.like(f"{year}-%"),
            ControlReportes.Enviado == True,
            ControlReportes.Facturado == False
        ).scalar() or 0
        
        # Calcular porcentajes
        porcentaje_facturado = round((reportes_facturados / total_reportes * 100) if total_reportes > 0 else 0, 2)
        porcentaje_pendiente = round((reportes_pendientes / total_reportes * 100) if total_reportes > 0 else 0, 2)
        
        return jsonify({
            'year': year,
            'total_reportes': total_reportes,
            'reportes_facturados': reportes_facturados,
            'reportes_pendientes': reportes_pendientes,
            'porcentaje_facturado': porcentaje_facturado,
            'porcentaje_pendiente': porcentaje_pendiente,
            'valor_total_facturado': float(valor_total_facturado),
            'valor_total_pendiente': float(valor_total_pendiente),
            'valor_total_general': float(valor_total_facturado + valor_total_pendiente)
        })
        
    except Exception as e:
        logger.error(f"❌ Error obteniendo estadísticas: {str(e)}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

# Manejadores de errores (mantenemos los existentes)
@app.errorhandler(404)
def not_found(error):
    logger.warning(f"404 error: {request.url}")
    if request.path.startswith('/api/'):
        return jsonify({'error': 'Endpoint no encontrado'}), 404
    if '/static/' in request.path:
        return 'Archivo no encontrado', 404
    return render_template('404.html') if os.path.exists('/var/www/html/TransmisionesMig/templates/404.html') else ('Página no encontrada', 404)

@app.errorhandler(500)
def internal_error(error):
    logger.error(f"500 error: {str(error)} - URL: {request.url}")
    db.session.rollback()
    if request.path.startswith('/api/'):
        return jsonify({'error': 'Error interno del servidor'}), 500
    return render_template('500.html') if os.path.exists('/var/www/html/TransmisionesMig/templates/500.html') else ('Error interno del servidor', 500)

@app.errorhandler(Exception)
def handle_exception(e):
    """Maneja excepciones no capturadas"""
    logger.error(f"Excepción no capturada: {str(e)} - URL: {request.url}")
    db.session.rollback()
    return jsonify({'error': 'Error interno del servidor'}), 500

# Función de inicialización (solo para Apache/WSGI)
def initialize_app():
    """Inicialización de la aplicación para producción"""
    logger.info("Aplicación cargada para producción con Apache - Versión con Clientes")
    
    try:
        with app.app_context():
            db.session.execute(text('SELECT 1'))
            logger.info("✅ Conexión a base de datos exitosa en producción")
            crear_tablas()
    except Exception as e:
        logger.error(f"❌ Error de conexión a base de datos en producción: {str(e)}")

# Solo ejecutar inicialización si NO estamos en modo de desarrollo
if __name__ != "__main__":
    with app.app_context():
        initialize_app()

# Función principal SOLO para desarrollo
if __name__ == "__main__":
    print("=" * 50)
    print("🚨 MODO DESARROLLO - SISTEMA CON CLIENTES")
    print("🚨 Esta aplicación maneja múltiples empresas cliente")
    print("=" * 50)
    
    logger.info("Iniciando aplicación con gestión de clientes...")
    
    try:
        with app.app_context():
            db.session.execute(text('SELECT 1'))
            logger.info("✅ Conexión a base de datos exitosa")
            crear_tablas()
    except Exception as e:
        logger.warning(f"❌ No se pudo conectar a la base de datos: {str(e)}")
    
    print("\n" + "=" * 50)
    print("URLs de prueba:")
    print("- http://localhost:8000/test")
    print("- http://localhost:8000/test-db")
    print("- http://localhost:8000/init-db")
    print("- http://localhost:8000/api/status")
    print("- http://localhost:8000/api/clientes")
    print("=" * 50 + "\n")
    
    app.run(
        host='0.0.0.0',
        port=8000,
        debug=True,
        threaded=True
    )

# Variable para WSGI (Apache)
application = app