import os
import uuid
from datetime import datetime
from flask import Blueprint, request, jsonify, session
from werkzeug.utils import secure_filename
from src.models.user import db, User
from src.models.company import Company
from src.models.invoice import Invoice
from src.models.expense_type import ExpenseType
from src.routes.auth import require_auth
from src.services.ocr_service import OCRService

invoice_bp = Blueprint('invoice', __name__)

# Configuración de archivos
UPLOAD_FOLDER = '/home/ubuntu/invoice-606-backend/uploads'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'pdf'}
MAX_FILE_SIZE = 16 * 1024 * 1024  # 16MB

# Crear directorio de uploads si no existe
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

def allowed_file(filename):
    """Verifica si el archivo tiene una extensión permitida"""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@invoice_bp.route('/invoices', methods=['GET'])
@require_auth
def get_invoices():
    """Obtener lista de facturas según el rol del usuario"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        status = request.args.get('status', '')
        expense_type = request.args.get('expense_type', '')
        search = request.args.get('search', '')
        
        query = Invoice.query
        
        # Filtrar según el rol
        if user_role == 'super_admin':
            # Super admin puede ver todas las facturas
            pass
        elif user_role == 'accountant':
            # Accountant solo puede ver facturas de su empresa
            query = query.filter_by(company_id=user_company_id)
        else:
            # Employee solo puede ver sus propias facturas
            query = query.filter_by(created_by_user_id=user_id)
        
        # Aplicar filtros
        if status:
            query = query.filter_by(status=status)
        
        if expense_type:
            query = query.filter_by(expense_type=expense_type)
        
        if search:
            query = query.filter(
                (Invoice.supplier_name.contains(search)) |
                (Invoice.supplier_rnc.contains(search)) |
                (Invoice.ncf.contains(search)) |
                (Invoice.invoice_number.contains(search))
            )
        
        # Ordenar por fecha de creación (más recientes primero)
        query = query.order_by(Invoice.created_at.desc())
        
        # Paginación
        invoices = query.paginate(
            page=page,
            per_page=per_page,
            error_out=False
        )
        
        return jsonify({
            'invoices': [invoice.to_dict() for invoice in invoices.items],
            'total': invoices.total,
            'pages': invoices.pages,
            'current_page': page,
            'per_page': per_page
        }), 200
        
    except Exception as e:
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices', methods=['POST'])
@require_auth
def create_invoice():
    """Crear nueva factura manualmente"""
    try:
        user_id = session.get('user_id')
        user_company_id = session.get('company_id')
        
        if not user_company_id:
            return jsonify({'error': 'Usuario debe estar asociado a una empresa'}), 400
        
        data = request.get_json()
        
        # Validar campos requeridos
        required_fields = ['supplier_name', 'supplier_rnc', 'ncf', 'invoice_date', 'invoiced_amount', 'expense_type']
        for field in required_fields:
            if not data.get(field):
                return jsonify({'error': f'Campo {field} es requerido'}), 400
        
        # Validar que el tipo de gasto exista
        expense_type = ExpenseType.query.get(data.get('expense_type'))
        if not expense_type:
            return jsonify({'error': 'Tipo de gasto inválido'}), 400
        
        # Generar número de factura interno
        invoice_number = f"INV-{datetime.now().strftime('%Y%m%d')}-{str(uuid.uuid4())[:8].upper()}"
        
        # Crear nueva factura
        new_invoice = Invoice(
            invoice_number=invoice_number,
            ncf=data.get('ncf'),
            ncf_modified=data.get('ncf_modified'),
            supplier_name=data.get('supplier_name'),
            supplier_rnc=data.get('supplier_rnc'),
            supplier_id_type=data.get('supplier_id_type', 'RNC'),
            invoice_date=datetime.strptime(data.get('invoice_date'), '%Y-%m-%d').date(),
            payment_date=datetime.strptime(data.get('payment_date'), '%Y-%m-%d').date() if data.get('payment_date') else None,
            invoiced_amount=float(data.get('invoiced_amount')),
            itbis_invoiced=float(data.get('itbis_invoiced', 0)),
            itbis_retained=float(data.get('itbis_retained', 0)),
            itbis_perceived=float(data.get('itbis_perceived', 0)),
            income_retention=float(data.get('income_retention', 0)),
            isr_perceived=float(data.get('isr_perceived', 0)),
            selective_consumption_tax=float(data.get('selective_consumption_tax', 0)),
            other_taxes=float(data.get('other_taxes', 0)),
            legal_tip=float(data.get('legal_tip', 0)),
            expense_type=data.get('expense_type'),
            expense_description=expense_type.name,
            status='pending',
            company_id=user_company_id,
            created_by_user_id=user_id
        )
        
        db.session.add(new_invoice)
        db.session.commit()
        
        return jsonify({
            'message': 'Factura creada exitosamente',
            'invoice': new_invoice.to_dict()
        }), 201
        
    except ValueError as e:
        return jsonify({'error': f'Error en formato de datos: {str(e)}'}), 400
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/upload', methods=['POST'])
@require_auth
def upload_invoice():
    """Subir imagen de factura para procesamiento OCR"""
    try:
        user_id = session.get('user_id')
        user_company_id = session.get('company_id')
        
        if not user_company_id:
            return jsonify({'error': 'Usuario debe estar asociado a una empresa'}), 400
        
        # Verificar que se subió un archivo
        if 'file' not in request.files:
            return jsonify({'error': 'No se encontró archivo'}), 400
        
        file = request.files['file']
        
        if file.filename == '':
            return jsonify({'error': 'No se seleccionó archivo'}), 400
        
        if not allowed_file(file.filename):
            return jsonify({'error': 'Tipo de archivo no permitido. Use PNG, JPG, JPEG o PDF'}), 400
        
        # Verificar tamaño del archivo
        file.seek(0, os.SEEK_END)
        file_size = file.tell()
        file.seek(0)
        
        if file_size > MAX_FILE_SIZE:
            return jsonify({'error': 'Archivo muy grande. Máximo 16MB'}), 400
        
        # Generar nombre único para el archivo
        filename = secure_filename(file.filename)
        unique_filename = f"{uuid.uuid4()}_{filename}"
        file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
        
        # Guardar archivo
        file.save(file_path)
        
        # Procesar con OCR
        ocr_service = OCRService()
        extracted_data, confidence = ocr_service.process_invoice_image(file_path)
        
        if not extracted_data:
            return jsonify({'error': 'No se pudieron extraer datos de la imagen'}), 400
        
        # Generar número de factura interno
        invoice_number = f"INV-{datetime.now().strftime('%Y%m%d')}-{str(uuid.uuid4())[:8].upper()}"
        
        # Crear factura con datos extraídos
        new_invoice = Invoice(
            invoice_number=invoice_number,
            ncf=extracted_data.get('ncf', ''),
            supplier_name=extracted_data.get('supplier_name', ''),
            supplier_rnc=extracted_data.get('supplier_rnc', ''),
            supplier_id_type='RNC',
            invoice_date=datetime.strptime(extracted_data.get('invoice_date'), '%Y-%m-%d').date() if extracted_data.get('invoice_date') else datetime.now().date(),
            invoiced_amount=extracted_data.get('invoiced_amount', 0),
            itbis_invoiced=extracted_data.get('itbis_invoiced', 0),
            expense_type=extracted_data.get('expense_type_suggestion', '06'),
            status='pending',
            ocr_processed=True,
            ocr_confidence=confidence,
            image_path=file_path,
            processed_at=datetime.utcnow(),
            company_id=user_company_id,
            created_by_user_id=user_id
        )
        
        # Obtener descripción del tipo de gasto
        expense_type = ExpenseType.query.get(new_invoice.expense_type)
        if expense_type:
            new_invoice.expense_description = expense_type.name
        
        db.session.add(new_invoice)
        db.session.commit()
        
        return jsonify({
            'message': 'Factura procesada exitosamente',
            'invoice': new_invoice.to_dict(),
            'extracted_data': extracted_data,
            'confidence': confidence
        }), 201
        
    except Exception as e:
        db.session.rollback()
        # Limpiar archivo si hubo error
        if 'file_path' in locals() and os.path.exists(file_path):
            os.remove(file_path)
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/<int:invoice_id>', methods=['GET'])
@require_auth
def get_invoice(invoice_id):
    """Obtener información de una factura específica"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        invoice = Invoice.query.get(invoice_id)
        if not invoice:
            return jsonify({'error': 'Factura no encontrada'}), 404
        
        # Verificar permisos
        if user_role == 'super_admin':
            # Super admin puede ver cualquier factura
            pass
        elif user_role == 'accountant':
            # Accountant puede ver facturas de su empresa
            if invoice.company_id != user_company_id:
                return jsonify({'error': 'No autorizado'}), 403
        else:
            # Employee solo puede ver sus propias facturas
            if invoice.created_by_user_id != user_id:
                return jsonify({'error': 'No autorizado'}), 403
        
        return jsonify({'invoice': invoice.to_dict()}), 200
        
    except Exception as e:
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/<int:invoice_id>', methods=['PUT'])
@require_auth
def update_invoice(invoice_id):
    """Actualizar información de una factura"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        invoice = Invoice.query.get(invoice_id)
        if not invoice:
            return jsonify({'error': 'Factura no encontrada'}), 404
        
        # Verificar permisos
        can_edit = False
        if user_role == 'super_admin':
            can_edit = True
        elif user_role == 'accountant' and invoice.company_id == user_company_id:
            can_edit = True
        elif user_role == 'employee' and invoice.created_by_user_id == user_id and invoice.status == 'pending':
            can_edit = True
        
        if not can_edit:
            return jsonify({'error': 'No autorizado para editar esta factura'}), 403
        
        data = request.get_json()
        
        # Campos que se pueden actualizar
        updatable_fields = [
            'ncf', 'ncf_modified', 'supplier_name', 'supplier_rnc', 'supplier_id_type',
            'invoice_date', 'payment_date', 'invoiced_amount', 'itbis_invoiced',
            'itbis_retained', 'itbis_perceived', 'income_retention', 'isr_perceived',
            'selective_consumption_tax', 'other_taxes', 'legal_tip', 'expense_type'
        ]
        
        for field in updatable_fields:
            if field in data:
                value = data[field]
                
                # Conversiones especiales
                if field in ['invoice_date', 'payment_date'] and value:
                    try:
                        value = datetime.strptime(value, '%Y-%m-%d').date()
                    except ValueError:
                        return jsonify({'error': f'Formato de fecha inválido para {field}'}), 400
                
                elif field in ['invoiced_amount', 'itbis_invoiced', 'itbis_retained', 'itbis_perceived',
                              'income_retention', 'isr_perceived', 'selective_consumption_tax',
                              'other_taxes', 'legal_tip'] and value is not None:
                    try:
                        value = float(value)
                    except ValueError:
                        return jsonify({'error': f'Valor numérico inválido para {field}'}), 400
                
                elif field == 'expense_type' and value:
                    # Validar que el tipo de gasto exista
                    expense_type = ExpenseType.query.get(value)
                    if not expense_type:
                        return jsonify({'error': 'Tipo de gasto inválido'}), 400
                    invoice.expense_description = expense_type.name
                
                setattr(invoice, field, value)
        
        db.session.commit()
        
        return jsonify({
            'message': 'Factura actualizada exitosamente',
            'invoice': invoice.to_dict()
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/<int:invoice_id>/approve', methods=['POST'])
@require_auth
def approve_invoice(invoice_id):
    """Aprobar una factura (solo accountant y super_admin)"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        if user_role not in ['accountant', 'super_admin']:
            return jsonify({'error': 'No autorizado para aprobar facturas'}), 403
        
        invoice = Invoice.query.get(invoice_id)
        if not invoice:
            return jsonify({'error': 'Factura no encontrada'}), 404
        
        # Verificar permisos
        if user_role == 'accountant' and invoice.company_id != user_company_id:
            return jsonify({'error': 'No autorizado para aprobar esta factura'}), 403
        
        if invoice.status == 'approved':
            return jsonify({'error': 'Factura ya está aprobada'}), 400
        
        invoice.status = 'approved'
        invoice.approved_by_user_id = user_id
        invoice.approved_at = datetime.utcnow()
        
        db.session.commit()
        
        return jsonify({
            'message': 'Factura aprobada exitosamente',
            'invoice': invoice.to_dict()
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/<int:invoice_id>/reject', methods=['POST'])
@require_auth
def reject_invoice(invoice_id):
    """Rechazar una factura (solo accountant y super_admin)"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        if user_role not in ['accountant', 'super_admin']:
            return jsonify({'error': 'No autorizado para rechazar facturas'}), 403
        
        invoice = Invoice.query.get(invoice_id)
        if not invoice:
            return jsonify({'error': 'Factura no encontrada'}), 404
        
        # Verificar permisos
        if user_role == 'accountant' and invoice.company_id != user_company_id:
            return jsonify({'error': 'No autorizado para rechazar esta factura'}), 403
        
        if invoice.status == 'rejected':
            return jsonify({'error': 'Factura ya está rechazada'}), 400
        
        invoice.status = 'rejected'
        invoice.approved_by_user_id = user_id
        invoice.approved_at = datetime.utcnow()
        
        db.session.commit()
        
        return jsonify({
            'message': 'Factura rechazada exitosamente',
            'invoice': invoice.to_dict()
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/invoices/<int:invoice_id>', methods=['DELETE'])
@require_auth
def delete_invoice(invoice_id):
    """Eliminar una factura"""
    try:
        user_role = session.get('user_role')
        user_company_id = session.get('company_id')
        user_id = session.get('user_id')
        
        invoice = Invoice.query.get(invoice_id)
        if not invoice:
            return jsonify({'error': 'Factura no encontrada'}), 404
        
        # Verificar permisos
        can_delete = False
        if user_role == 'super_admin':
            can_delete = True
        elif user_role == 'accountant' and invoice.company_id == user_company_id:
            can_delete = True
        elif user_role == 'employee' and invoice.created_by_user_id == user_id and invoice.status == 'pending':
            can_delete = True
        
        if not can_delete:
            return jsonify({'error': 'No autorizado para eliminar esta factura'}), 403
        
        # Eliminar archivo de imagen si existe
        if invoice.image_path and os.path.exists(invoice.image_path):
            try:
                os.remove(invoice.image_path)
            except Exception:
                pass  # No fallar si no se puede eliminar el archivo
        
        db.session.delete(invoice)
        db.session.commit()
        
        return jsonify({'message': 'Factura eliminada exitosamente'}), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

@invoice_bp.route('/expense-types', methods=['GET'])
@require_auth
def get_expense_types():
    """Obtener lista de tipos de gastos"""
    try:
        expense_types = ExpenseType.query.filter_by(is_active=True).all()
        return jsonify({
            'expense_types': [expense_type.to_dict() for expense_type in expense_types]
        }), 200
        
    except Exception as e:
        return jsonify({'error': f'Error interno del servidor: {str(e)}'}), 500

