<?php
// CARGA MAESTRA DE CONFIGURACIÓN Y BRANDING
require_once(__DIR__ . '/core/init.php');

// === UNIFICACIÓN DE ENDPOINTS API ===
const API_CLIENTS_READ_CONTACT_URL = 'db/clients-read-contact-data.php';
const API_SERVICES_READ_ALL_URL = 'db/services-read-all.php';
const API_INVOICE_READ_URL = 'db/invoice-read.php';
const API_INVOICE_CREATE_URL = 'db/invoice-create.php';
const API_INVOICE_UPDATE_URL = 'db/invoice-update.php';
const API_INVOICE_DELETE_URL = 'db/invoice-delete.php';
const API_INVOICE_STATUS_UPDATE_URL = 'db/invoice-status-update.php';


$db_error_message = null;
$company_logo_url = 'core/img/Placeholder.webp';
$company_name_from_db = 'Nombre Del Negocio';
$contact_name_from_db = 'Nombre De Contacto';
$contact_email_from_db = 'correo@ejemplo.com';
$contact_phone_from_db = 'N/A';

try {
    // MITIGACIÓN SQLI: Sentencia Preparada
    $stmt_config = $pdo->prepare("SELECT * FROM business_info WHERE id = :id");
    $stmt_config->execute([':id' => 1]);
    $config = $stmt_config->fetch(PDO::FETCH_ASSOC);

    if ($config) {
        $company_name_from_db = htmlspecialchars($config['company_name'] ?? 'Nombre Del Negocio', ENT_QUOTES, 'UTF-8');
        $contact_name_from_db = htmlspecialchars($config['full_name'] ?? 'Nombre De Contacto', ENT_QUOTES, 'UTF-8');
        $contact_email_from_db = htmlspecialchars($config['site_email'] ?? 'correo@ejemplo.com', ENT_QUOTES, 'UTF-8');
        $contact_phone_from_db = htmlspecialchars($config['phone_primary'] ?? 'N/A', ENT_QUOTES, 'UTF-8');
        
        if (!empty($config['logo_url'])) {
            $company_logo_url = htmlspecialchars($config['logo_url'], ENT_QUOTES, 'UTF-8');
        }

    } else {
        $db_error_message = 'No Se Encontró La Configuración';
    }
    
} catch (PDOException $e) {
    error_log("Error PDO al cargar configuración desde business_info: " . $e->getMessage());
    $db_error_message = 'Error de Base de Datos: No se pudo cargar la configuración.';
} catch (Exception $e) {
    error_log("Error general al cargar configuración desde business_info: " . $e->getMessage());
    $db_error_message = 'Error inesperado.';
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Centro De Control De Facturación <?php echo htmlspecialchars($branding['full_title']); ?></title>
    <meta name="robots" content="noindex, nofollow">
    
    <link rel="icon" type="image/png" href="<?php echo htmlspecialchars($branding['favicon']); ?>">
    <link rel="apple-touch-icon" href="<?php echo htmlspecialchars($branding['favicon']); ?>">
    
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="<?php echo htmlspecialchars($google_font_url); ?>">

    <?php include 'files/gtm-head.php'; ?>
    
    <script src="https://unpkg.com/lucide@latest"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
    
    <script src="https://unpkg.com/imask"></script>

    <link rel="stylesheet" href="style.css">
    <script src="files/header-manager.js"></script>
    
</head>
<body data-page-title="Centro De Control De Facturación"
      data-page-subtitle="Administra, Crea Y Organiza Los Cobros Por Tus Servicios"
      data-page-icon="wallet">

<input type="hidden" id="csrf-token-php" value="<?= $_SESSION['csrf_token'] ?>">

    <div id="toast-container" class="toast-container"></div>
    
<?php include 'files/gtm-body.php'; ?> 

<div class="relative min-h-screen md:flex">
    <div id="sidebar-overlay" class="fixed inset-0 bg-black bg-opacity-50 z-30 hidden md:hidden"></div>
    <div id="task-panel-overlay" class="fixed inset-0 bg-black/60 z-40 hidden transition-opacity duration-300"></div>  
    
    <?php include 'menu.php'; ?>
    
    <main class="flex-1 overflow-y-auto">
        <header class="bg-white shadow-sm p-4 flex justify-between items-center sticky top-0 z-20">
            <button id="mobile-menu-button" class="md:hidden text-gray-600 hover:text-gray-800">
                <i data-lucide="menu" class="w-6 h-6"></i>
            </button>
            <div class="page-header-container">
                <h2 id="page-title"></h2>
                <p id="page-subtitle"></p>
            </div>
        </header>

        <div id="content-area" class="p-4 md:p-8 space-y-8">
            
           <section id="dashboard-stats-section">
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        <div class="stat-card bg-white p-6 rounded-xl shadow-md flex items-center space-x-4 border-l-4 border-[var(--color-highlight)]">
            <i data-lucide="users" class="w-12 h-12 text-[var(--color-secondary)]"></i>
            <div>
                <h3 class="text-lg font-black text-gray-500 mb-1 uppercase">Clientes Facturados</h3>
                <p id="stats-clients-count" class="text-5xl font-bold text-[var(--color-primary)] uppercase">0</p>
            </div>
        </div>

        <div class="stat-card bg-white p-6 rounded-xl shadow-md flex items-center space-x-4 border-l-4 border-[var(--color-highlight)]">
            <i data-lucide="wallet" class="w-12 h-12 text-[var(--color-secondary)]"></i>
            <div>
                <h3 class="text-lg font-black text-gray-500 mb-1 uppercase">Valor Total Pagado</h3>
                <p id="stats-month-total" class="text-5xl font-bold text-green-600 uppercase">$0</p>
            </div>
        </div>

        <div class="stat-card bg-white p-6 rounded-xl shadow-md flex items-center space-x-4 border-l-4 border-[var(--color-highlight)]">
            <i data-lucide="bell" class="w-12 h-12 text-[var(--color-secondary)]"></i>
            <div>
                <h3 class="text-lg font-black text-gray-500 mb-1 uppercase">Facturas Pendientes</h3>
                <p id="stats-pending-count" class="text-5xl font-bold text-[var(--color-secondary)] uppercase">0</p>
            </div>
        </div>
    </div>
</section>

            <section id="list-view-section">
                <div class="bg-white p-6 rounded-xl shadow-md">
                    <div class="flex flex-col md:flex-row justify-between items-center mb-6 gap-4">
                        <h3 class="text-2xl font-extrabold text-gray-800 flex items-center gap-2"><i data-lucide="banknote" class="w-7 h-7 text-[var(--color-primary)]"></i> TODAS LAS FACTURAS</h3>
                        
                        <button id="show-generator-btn" class="w-full bg-[var(--color-secondary)] hover:opacity-90 text-white font-black py-2.5 px-4 rounded-lg uppercase sm:w-auto flex items-center justify-center gap-2">
                            <i data-lucide="plus" class="w-5 h-5 mr-2"></i> Nueva Factura
                        </button>
                    </div>
                    <div class="flex flex-col md:flex-row gap-4 mb-6">
                        <div class="input-with-icon w-full">
                            <i data-lucide="search" class="search-icon w-5 h-5"></i>
                            <input type="text" id="list-search" placeholder="Buscar Por Nombre..." class="w-full p-3 border border-gray-300 rounded-lg">
                        </div>
                        <select id="month-filter" class="w-full md:w-auto p-3 border border-gray-300 rounded-lg bg-white"></select>
                        <select id="list-filter-status" class="w-full md:w-auto p-3 border border-gray-300 rounded-lg bg-white"></select>
                    </div>
                    <div class="overflow-x-auto pt-4">
                        <table class="min-w-full bg-white responsive-table-stack">
                            <thead class="bg-gray-50">
                                <tr class="text-left text-gray-500 uppercase text-sm">
                                    <th class="py-3 px-6 font-semibold">Fecha</th>
                                    <th class="py-3 px-6 font-semibold">Cliente</th>
                                    <th class="py-3 px-6 font-semibold">Servicio</th>
                                    <th class="py-3 px-6 font-semibold">Monto</th>
                                    <th class="py-3 px-6 font-semibold">Estado</th>
                                    <th class="py-3 px-6 font-semibold text-center">Acciones</th>
                                </tr>
                            </thead>
                            <tbody id="invoicesTableBody"></tbody>
                        </table>
                        <p id="no-invoices-msg" class="text-center text-gray-500 py-8 hidden">AÚN NO HAS GENERADO NINGUNA FACTURA</p>
                    </div>
                </div>
            </section>
        </div>
    </main>
</div>

<section id="generator-view-section" class="hidden">
    <div id="generator-overlay" class="fixed inset-0 bg-black bg-opacity-50 z-40"></div>
    <div id="generator-panel" class="fixed inset-y-0 right-0 w-full max-w-6xl bg-gray-100 shadow-xl z-50 transform translate-x-full transition-transform duration-300 ease-in-out">
        <div class="grid grid-cols-1 lg:grid-cols-5 h-full">
            <div class="lg:col-span-2 bg-gray-100 p-6 overflow-y-auto space-y-6 h-full">
                <div class="modal-header-container rounded-xl">
                    <h1 id="generator-title" class="modal-primary-title text-3xl font-black uppercase">Crear Factura</h1>
                </div>
                <input type="hidden" id="editing-invoice-id">

                <div class="space-y-4">
                    <h2 class="text-2xl font-black text-[var(--color-primary)] flex items-center gap-2 uppercase">
                        <i data-lucide="user-check" class="w-5 h-5 text-[var(--color-primary)]"></i> Información del Cliente
                    </h2>

                    <div id="contact-selection-area">
                        <div class="space-y-2">
                            <label for="clientSearch" class="text-sm font-semibold text-gray-700">Buscar Cliente</label>
                            <div class="relative input-with-icon">
                                <i data-lucide="search" class="search-icon w-5 h-5"></i>
                                <input type="text" id="clientSearch" placeholder="Nombre Del Cliente..." autocomplete="off" class="w-full p-2.5 border border-gray-300 rounded-lg">
                                <div id="client-suggestions" class="absolute w-full bg-white border rounded-md mt-1 shadow-lg z-20 hidden"></div>
                            </div>
                        </div>
                    </div>

                    <div id="selected-contact-display" class="hidden items-center justify-between p-3 bg-blue-50 border border-blue-200 rounded-lg">
                        <div class="flex items-center gap-3">
                            <i data-lucide="user-check" class="w-6 h-6 text-blue-800"></i>
                            <div>
                                <p class="font-bold text-blue-800" id="selected-contact-name"></p>
                                <p class="text-xs text-blue-600" id="selected-contact-email"></p>
                            </div>
                        </div>
                        <button id="change-contact-btn" class="text-sm text-blue-600 hover:underline">Cambiar</button>
                    </div>
                </div>

                <div class="space-y-4">
                    <h2 class="text-2xl font-black text-[var(--color-primary)] flex items-center gap-2 uppercase">
                        <i data-lucide="clipboard-list" class="w-5 h-5 text-[var(--color-primary)]"></i> Detalles Del Servicio
                    </h2>
                    <select id="tipoServicio" class="w-full p-2.5 border border-gray-300 rounded-lg"></select>
                </div>
                <div class="space-y-4">
                    <h2 class="text-2xl font-black text-[var(--color-primary)] flex items-center gap-2 uppercase">
                        <i data-lucide="percent" class="w-5 h-5 text-[var(--color-primary)]"></i> Impuestos (Taxes)
                    </h2>
                    <input type="number" id="tax-rate" value="0" min="0" step="0.1" class="w-full p-2.5 border border-gray-300 rounded-lg">
                </div>

                <div id="digital-link-container" class="hidden space-y-2 bg-blue-50 p-3 rounded-lg border border-blue-200 mt-4">
                    <label class="text-xs font-bold text-blue-800 uppercase flex items-center gap-2">
                        <i data-lucide="link" class="w-4 h-4"></i> Enlace Digital (Cliente)
                    </label>
                    <div class="flex gap-2">
                        <input type="text" id="sidebar-quote-link" readonly class="w-full text-xs p-2 border border-blue-300 rounded text-gray-600 bg-white focus:outline-none select-all">
                        <button type="button" id="sidebar-copy-btn" class="bg-blue-600 text-white p-2 rounded hover:bg-blue-700 transition-colors" title="Copiar">
                            <i data-lucide="copy" class="w-4 h-4"></i>
                        </button>
                        <a id="sidebar-open-btn" href="#" target="_blank" class="bg-blue-600 text-white p-2 rounded hover:bg-blue-700 transition-colors flex items-center" title="Abrir">
                            <i data-lucide="external-link" class="w-4 h-4"></i>
                        </a>
                    </div>
                    <p class="text-[10px] text-blue-600 font-bold uppercase">
                        * Comparte este enlace con tu cliente para que vea la factura.
                    </p>
                </div>

                <div class="flex flex-col space-y-3 pt-4">  
                    <button id="save-invoice-btn" class="w-full bg-[var(--color-primary)] hover:opacity-90 text-white font-black py-2.5 px-4 rounded-lg uppercase sm:w-auto flex items-center justify-center gap-2">
                        <i data-lucide="save" class="w-6 h-6 mr-2"></i> Guardar Cambios
                    </button>
                    <button id="download-pdf-btn" class="w-full bg-gray-300 hover:bg-gray-400 text-gray-800 font-black py-2.5 px-4 rounded-lg uppercase sm:w-auto flex items-center justify-center gap-2">
                        <i data-lucide="download" class="w-6 h-6 mr-2"></i> Descargar Digital
                    </button>
                    <button id="back-to-list-btn" class="bg-gray-300 hover:bg-gray-400 text-gray-800 w-full p-3 rounded-lg uppercase font-bold flex items-center justify-center">
                        <i data-lucide="arrow-left" class="w-6 h-6 mr-2"></i> Cancelar
                    </button>
                </div>
            </div>
            <div class="lg:col-span-3 bg-white p-2 overflow-y-auto h-full">
                <div id="pdf-preview" class="p-8 relative">
                    <div id="invoice-status-seal-container" class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 rotate-[-45deg] opacity-10 pointer-events-none z-10 hidden">
                        <span id="invoice-status-seal" class="text-9xl font-black p-4 border-8 border-current rounded-lg"></span>
                    </div>
                    <div id="invoice-content" class="relative"></div>
                </div>
            </div>
        </div>
    </div>
</section>

<div id="status-modal-overlay" class="fixed inset-0 bg-gray-900 bg-opacity-90 flex items-center justify-center hidden z-50">
    <div id="status-modal" class="bg-white rounded-xl shadow-2xl w-full max-w-sm m-4 transform transition-all duration-300 scale-95 opacity-0 text-center">
        <div class="modal-header-container rounded-t-xl pt-6">
            <h3 class="modal-primary-title text-4xl font-black text-[var(--color-highlight)] uppercase leading-none">ACTUALIZAR</h3>
            
        </div>
        <div class="p-8">
            <div class="flex justify-center mb-6"><i data-lucide="refresh-cw" class="w-16 h-16 text-[var(--color-primary)]"></i></div>
            <input type="hidden" id="modal-invoice-id">
            <p class="text-[var(--color-primary)] mb-6 uppercase text-lg font-bold">NUEVO ESTADO</p>
            <div class="mb-6">
                <select id="modal-status-select" class="w-full p-3 border-2 border-gray-200 rounded-lg text-center font-bold text-gray-700 uppercase bg-white"></select>
            </div>
            <div class="flex flex-col sm:flex-row justify-center space-y-2 sm:space-y-0 sm:space-x-4">
                <button id="modal-cancel-btn" class="w-full bg-gray-300 text-gray-800 font-black py-2.5 px-4 rounded-lg uppercase">CANCELAR</button>
                <button id="modal-save-status-btn" class="w-full bg-[var(--color-primary)] text-white font-black py-2.5 px-4 rounded-lg uppercase">GUARDAR</button>
            </div>
        </div>
    </div>
</div>

<div id="confirmDeleteModal" class="fixed inset-0 bg-gray-900 bg-opacity-90 flex items-center justify-center hidden z-50">
    <div class="bg-white rounded-xl shadow-2xl w-full max-w-sm m-4 transform transition-all duration-300 scale-95 opacity-0 text-center">
        
        <div class="modal-header-container rounded-t-xl pt-6">
            <h3 class="modal-primary-title text-4xl font-black text-[var(--color-highlight)] uppercase leading-none">
                ADVERTENCIA
            </h3>
        </div>

        <div class="p-8">
            <div class="flex justify-center mb-6">
                <i data-lucide="trash-2" class="w-16 h-16 text-[var(--color-secondary)]"></i>
            </div>

            <p class="text-[var(--color-primary)] mb-6 uppercase text-lg font-bold leading-tight">
                ¿ESTÁS SEGURO DE QUE DESEAS ELIMINAR ESTE <span id="confirm-item-type" class="font-black text-[var(--color-secondary)] inline">ELEMENTO</span>?
            </p>

            <div class="flex flex-col sm:flex-row justify-center space-y-2 sm:space-y-0 sm:space-x-4">
                <button type="button" id="cancel-delete-btn" class="w-full bg-[var(--color-primary)] hover:opacity-90 text-white font-black py-2.5 px-4 rounded-lg uppercase sm:w-auto flex items-center justify-center gap-2">
                    <i data-lucide="x-circle" class="w-5 h-5"></i> CANCELAR
                </button>
                <button type="button" id="confirm-delete-button" class="w-full bg-[var(--color-secondary)] hover:opacity-90 text-white font-black py-2.5 px-4 rounded-lg uppercase sm:w-auto flex items-center justify-center gap-2 shadow-md transition-all duration-200">
                    <i data-lucide="trash-2" class="w-5 h-5"></i> ELIMINAR
                </button>
            </div>
            <p class="mt-6 uppercase text-xs font-black text-gray-500 tracking-wider">ESTA ACCIÓN NO SE PUEDE DESHACER</p>
        </div>
    </div>
</div>

<div id="invoiceSuccessModal" 
     class="fixed inset-0 bg-gray-900 bg-opacity-90 flex items-center justify-center hidden z-50"
     onclick="/* No auto close */">
    
    <div class="bg-white rounded-xl shadow-2xl w-full max-w-lg m-4 transform transition-all duration-300 scale-95 opacity-0 text-center">
        
        <div class="modal-header-container rounded-t-xl pt-6">
            <h3 class="modal-primary-title text-3xl font-black text-green-600 uppercase leading-none">
                ¡FACTURA GUARDADA!
            </h3>
        </div>

        <div class="p-8">
            <div class="flex justify-center mb-6">
                <div class="bg-green-100 p-4 rounded-full">
                    <i data-lucide="check-check" class="w-12 h-12 text-green-600"></i>
                </div>
            </div>

            <p class="text-gray-600 mb-2 font-bold uppercase">
                Enlace digital para tu cliente:
            </p>
            
            <div class="flex gap-2 mb-6">
                <input type="text" id="success-quote-link" readonly 
                       class="w-full p-3 border-2 border-green-200 rounded-lg text-gray-700 bg-green-50 focus:outline-none font-medium text-sm">
                
                <button id="success-copy-btn" class="bg-[var(--color-primary)] hover:bg-[var(--color-highlight)] text-white p-3 rounded-lg transition-colors flex items-center justify-center" title="Copiar">
                    <i data-lucide="copy" class="w-5 h-5"></i>
                </button>
                
                <a id="success-open-btn" href="#" target="_blank" class="bg-[var(--color-secondary)] hover:opacity-90 text-white p-3 rounded-lg transition-colors flex items-center justify-center" title="Abrir">
                    <i data-lucide="external-link" class="w-5 h-5"></i>
                </a>
            </div>

            <div class="flex justify-center">
                <button type="button" 
                        id="close-success-modal-btn"
                        class="w-full bg-gray-800 hover:bg-gray-700 text-white font-black py-3 px-6 rounded-lg uppercase flex items-center justify-center gap-2 transition-colors">
                    <i data-lucide="x" class="w-5 h-5"></i> CERRAR Y ACTUALIZAR
                </button>
            </div>
        </div>
    </div>
</div>

<script>
// ====================================================================================================================
// BLOQUE DE CÓDIGO JAVASCRIPT PRINCIPAL
// ====================================================================================================================

    document.addEventListener('DOMContentLoaded', function() {

        // VARIABLES DE INICIALIZACIÓN Y SEGURIDAD
        if (window.jspdf) { window.jsPDF = window.jspdf.jsPDF; }
        const CSRF_TOKEN = document.getElementById('csrf-token-php').value;
        // CORRECCIÓN CRÍTICA: Obtener el user_id de la sesión PHP para enviarlo en las peticiones UPDATE/CREATE
        const USER_ID = <?php echo $user_id_session ?? 1; ?>; 

        // MAPA DE TRADUCCIÓN DE ESTADOS (Lógica en Inglés <-> Visualización en Español)
        const STATUS_MAP = {
            'generated': 'GENERADA',
            'sent': 'ENVIADA',
            'cancelled': 'CANCELADA',
            'overdue': 'ATRASADA',
            'paid': 'PAGADA',
            'enviado': 'ENVIADA', // Permite corrección de errores comunes en la DB
            'enviada': 'ENVIADA', 
            'pagada': 'PAGADA'
        };

        const SPANISH_TO_ENGLISH = {
            'GENERADA': 'generated',
            'ENVIADA': 'sent',
            'CANCELADA': 'cancelled',
            'ATRASADA': 'overdue',
            'PAGADA': 'paid'
        };

        const MASTER_STATUSES_LIST = ['generated', 'sent', 'cancelled', 'overdue', 'paid'];


        // URLs Centralizadas
        const API_URLS = {
            CLIENTS_READ: '<?php echo API_CLIENTS_READ_CONTACT_URL; ?>',
            SERVICES_READ: '<?php echo API_SERVICES_READ_ALL_URL; ?>',
            INVOICE_READ: '<?php echo API_INVOICE_READ_URL; ?>',
            INVOICE_CREATE: '<?php echo API_INVOICE_CREATE_URL; ?>',
            INVOICE_UPDATE: '<?php echo API_INVOICE_UPDATE_URL; ?>',
            INVOICE_DELETE: '<?php echo API_INVOICE_DELETE_URL; ?>',
            INVOICE_STATUS_UPDATE: '<?php echo API_INVOICE_STATUS_UPDATE_URL; ?>'
        };

        // CACHÉ DE DATOS GLOBALES
        let allClients = [];
        let allServices = [];
        let allInvoices = {};
        let nextAvailableInvoiceNumber = 1;
        let selectedContact = null;
        const currentMonthYear = new Date().toISOString().substring(0, 7);

        // CACHÉ DE ELEMENTOS DEL DOM
        const elements = {
            generatorView: document.getElementById('generator-view-section'),
            generatorPanel: document.getElementById('generator-panel'),
            generatorOverlay: document.getElementById('generator-overlay'),
            invoicesTableBody: document.getElementById('invoicesTableBody'),
            noInvoicesMsg: document.getElementById('no-invoices-msg'),
            showGeneratorBtn: document.getElementById('show-generator-btn'),
            saveInvoiceBtn: document.getElementById('save-invoice-btn'),
            downloadPdfBtn: document.getElementById('download-pdf-btn'),
            backToListBtn: document.getElementById('back-to-list-btn'),
            listSearch: document.getElementById('list-search'),
            monthFilter: document.getElementById('month-filter'),
            listFilterStatus: document.getElementById('list-filter-status'),
            generatorTitle: document.getElementById('generator-title'),
            editingInvoiceId: document.getElementById('editing-invoice-id'),
            clientSearch: document.getElementById('clientSearch'),
            clientSuggestions: document.getElementById('client-suggestions'),
            contactSelectionArea: document.getElementById('contact-selection-area'),
            selectedContactDisplay: document.getElementById('selected-contact-display'),
            selectedContactName: document.getElementById('selected-contact-name'),
            selectedContactEmail: document.getElementById('selected-contact-email'),
            changeContactBtn: document.getElementById('change-contact-btn'),
            tipoServicio: document.getElementById('tipoServicio'),
            taxRate: document.getElementById('tax-rate'),
            invoiceContent: document.getElementById('invoice-content'),
            statusModalOverlay: document.getElementById('status-modal-overlay'),
            modalInvoiceId: document.getElementById('modal-invoice-id'),
            modalStatusSelect: document.getElementById('modal-status-select'),
            invoiceStatusSealContainer: document.getElementById('invoice-status-seal-container'),
            invoiceStatusSeal: document.getElementById('invoice-status-seal'),
            confirmDeleteModal: document.getElementById('confirmDeleteModal'),
            confirmDeleteButton: document.getElementById('confirm-delete-button')
        };
        let dynamicElements = {};

        // VARIABLES PHP INYECTADAS
        const companyLogoUrl = '<?php echo $company_logo_url; ?>';
        const companyName = '<?php echo $company_name_from_db; ?>';
        const contactName = '<?php echo $contact_name_from_db; ?>';
        const contactEmail = '<?php echo $contact_email_from_db; ?>';
        const contactPhone = '<?php echo $contact_phone_from_db; ?>';

        // TEMPLATE HTML PRINCIPAL DE LA FACTURA
        const invoiceTemplateHTML = `<div class="flex justify-between items-start mb-10"><div><img src="${companyLogoUrl}" alt="Logo" class="h-16 mb-4"><h2 class="text-2xl font-black text-gray-800">${companyName}</h2><p class="text-gray-600">${contactName}</p><p class="text-gray-600">${contactEmail}</p><p class="text-gray-600">${contactPhone}</p></div><div class="text-right"><h1 class="text-5xl font-black text-gray-300 tracking-wider">INVOICE</h1><p><strong>Date:</strong> <span id="previewDate"></span></p><p><strong>Invoice No.:</strong> <span id="previewInvoiceId"></span></p></div></div><div class="bg-gray-50 p-4 rounded-lg mb-8"><h3 class="font-bold text-gray-500 text-sm tracking-wider">INVOICE TO:</h3><p id="previewContactName" contenteditable="true"></p><p id="previewContactAddress" contenteditable="true"></p><p id="previewContactEmail" contenteditable="true"></p><p id="previewContactPhone" contenteditable="true"></p></div><table class="w-full mb-8"><thead class="bg-gray-800 text-white"><tr><th class="text-left p-3 rounded-tl-md">DESCRIPTION</th><th class="text-right p-3">QTY.</th><th class="text-right p-3">UNIT PRICE</th><th class="text-right p-3 rounded-tr-md">TOTAL</th><th class="p-3 rounded-tr-md"></th></tr></thead><tbody id="invoice-items"></tbody></table><button id="addItemBtn" class="bg-gray-100 border w-full p-2.5 rounded-lg text-sm mb-6 flex items-center justify-center text-gray-700 hover:bg-gray-200"><i data-lucide="plus-circle" class="w-5 h-5 mr-2"></i> AGREGAR ADICIONAL</button><div class="flex justify-end mt-4"><div class="w-full md:w-1/2"><div class="flex justify-between p-2"><span>Subtotal</span><span id="previewSubtotal"></span></div><div class="flex justify-between p-2 border-b"><span>Tax (<span id="previewTaxRate">0</span>%)</span><span id="previewTaxAmount"></span></div><div class="flex justify-between font-bold text-xl bg-[var(--color-highlight)] p-3 rounded-md"><span>TOTAL</span><span id="previewTotal"></span></div></div></div><div class="mt-16 text-xs text-gray-500"><h4 class="font-bold mb-1">Terms and Conditions</h4><p contenteditable="true">This invoice is due upon receipt.</p></div>`;


// ====================================================================================================================
// FUNCIONES DE UTILIDAD (UTILITIES)
// ====================================================================================================================

    const escapeHTML = (str) => {
        if (!str) return '';
        return String(str).replace(/[&<>'"]/g, 
            tag => ({'&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;'}[tag]));
    };

    const applyStatusSeal = (status) => {
        const sealElement = elements.invoiceStatusSeal;
        const sealContainer = elements.invoiceStatusSealContainer;
        if (!sealElement || !sealContainer) return;

        const s = status ? status.toLowerCase() : null;
        sealContainer.classList.remove('hidden');

        if (s === 'paid' || s === 'pagada') {
            sealElement.textContent = 'PAID';
            sealElement.classList.remove('text-red-500', 'border-red-500');
            sealElement.classList.add('text-green-500', 'border-green-500');
        } else if (['generated', 'sent', 'overdue', 'generada', 'enviada', 'atrasada', 'enviado', 'cancelled', 'cancelada'].includes(s)) {
            sealElement.textContent = 'UNPAID';
            sealElement.classList.remove('text-green-500', 'border-green-500');
            sealElement.classList.add('text-red-500', 'border-red-500');
        } else {
            sealContainer.classList.add('hidden');
        }
    };

    const formatStatusText = (status) => {
        const s = status ? status.toLowerCase() : '';
        return STATUS_MAP[s] || s.toUpperCase();
    };
    
    const getStatusClass = (status) => {
        const s = status.toLowerCase();
        if (s === 'paid' || s === 'pagada') return 'bg-green-100 text-green-800';
        if (s === 'sent' || s === 'enviada' || s === 'enviado') return 'bg-blue-100 text-blue-800';
        if (s === 'cancelled' || s === 'cancelada') return 'bg-gray-100 text-gray-800';
        if (s === 'overdue' || s === 'atrasada') return 'bg-red-100 text-red-800';
        return 'bg-yellow-100 text-yellow-800';
    };

    const openModal = (modalId) => {
        const modal = document.getElementById(modalId);
        if (!modal) return;
        const modalBox = modal.querySelector('div:first-of-type');
        modal.classList.remove('hidden');
        setTimeout(() => { modalBox.classList.remove('scale-95', 'opacity-0'); modalBox.classList.add('scale-100', 'opacity-100'); }, 50);
        if (typeof lucide !== 'undefined') lucide.createIcons();
    };
    
    const closeModal = (modalId) => {
        const modal = document.getElementById(modalId);
        if (!modal) return;
        const modalBox = modal.querySelector('div:first-of-type');
        modalBox.classList.remove('scale-100', 'opacity-100');
        modalBox.classList.add('scale-95', 'opacity-0');
        setTimeout(() => { modal.classList.add('hidden'); }, 300);
    };
    window.closeModal = closeModal; 
    window.openModal = openModal;

    const setupQuickLinkListeners = () => {
        document.querySelectorAll('.copy-row-link-btn').forEach(button => {
            button.onclick = null;
            button.addEventListener('click', (event) => {
                event.stopPropagation();
                const token = button.dataset.token;
                
                const path = window.location.pathname;
                const directory = path.substring(0, path.lastIndexOf('/'));
                const fullLink = `${window.location.origin}${directory}/invoice-view.php?token=${token}`;
                
                navigator.clipboard.writeText(fullLink).then(() => {
                    if (typeof showToast === 'function') {
                        showToast('Enlace de factura copiado', 'success');
                    } else {
                        alert('Enlace copiado');
                    }
                }).catch(err => {
                    console.error('Error al copiar:', err);
                });
            });
        });
    };

// ====================================================================================================================
// MANEJO DE ESTADO Y DATOS
// ====================================================================================================================

    const bindDynamicElements = () => {
        dynamicElements = {
            invoiceItemsBody: document.getElementById('invoice-items'),
            addItemBtn: document.getElementById('addItemBtn'),
            previewContactName: document.getElementById('previewContactName'),
            previewContactAddress: document.getElementById('previewContactAddress'),
            previewContactEmail: document.getElementById('previewContactEmail'),
            previewContactPhone: document.getElementById('previewContactPhone'),
            previewDate: document.getElementById('previewDate'),
            previewInvoiceId: document.getElementById('previewInvoiceId'),
            previewSubtotal: document.getElementById('previewSubtotal'),
            previewTaxRate: document.getElementById('previewTaxRate'),
            previewTaxAmount: document.getElementById('previewTaxAmount'),
            previewTotal: document.getElementById('previewTotal')
        };

        if (dynamicElements.addItemBtn) {
            dynamicElements.addItemBtn.addEventListener('click', () => {
                dynamicElements.invoiceItemsBody.appendChild(createItemRow());
                if (typeof lucide !== 'undefined') { lucide.createIcons(); }
            });
        }
        if (dynamicElements.invoiceItemsBody) {
            dynamicElements.invoiceItemsBody.addEventListener('input', recalculateTotal);
            dynamicElements.invoiceItemsBody.addEventListener('blur', (e) => {
                if (e.target.matches('.item-unit-price')) {
                    e.target.textContent = `$${(parseFloat(e.target.textContent.replace(/[^\d.]/g, '')) || 0).toFixed(2)}`;
                } else if (e.target.matches('.item-qty')) {
                    e.target.textContent = `${(parseInt(e.target.textContent) || 1)}`;
                }
            }, true);
        }
        if (elements.taxRate) elements.taxRate.addEventListener('input', recalculateTotal);
    };

    const resetGeneratorForm = () => {
        selectedContact = null;
        elements.editingInvoiceId.value = '';
        elements.contactSelectionArea.classList.remove('hidden');
        elements.selectedContactDisplay.classList.add('hidden');
        elements.clientSearch.value = '';
        elements.tipoServicio.value = '';
        elements.taxRate.value = 0;
        if (dynamicElements.invoiceItemsBody) dynamicElements.invoiceItemsBody.innerHTML = '';
        if (dynamicElements.invoiceItemsBody) { dynamicElements.invoiceItemsBody.appendChild(createItemRow("Nuevo Ítem", 0.00, 1)); }
        
        const digitalLinkContainer = document.getElementById('digital-link-container');
        if (digitalLinkContainer) digitalLinkContainer.classList.add('hidden');

        updatePreview();
        applyStatusSeal(null);
    };
    
    const handleContactSelection = (contact) => {
        selectedContact = contact;
        selectedContact.name = escapeHTML(selectedContact.name);
        selectedContact.email = escapeHTML(selectedContact.email);
        selectedContact.street_address = escapeHTML(selectedContact.street_address || contact.address || '');

        elements.contactSelectionArea.classList.add('hidden');
        elements.selectedContactName.textContent = selectedContact.name;
        elements.selectedContactEmail.textContent = selectedContact.email;
        elements.selectedContactDisplay.classList.remove('hidden');
        elements.clientSuggestions.classList.add('hidden');
        elements.clientSearch.value = '';
        updatePreview();
    };

    const updatePreview = () => {
        if (!dynamicElements.previewContactName) return;

        dynamicElements.previewContactName.textContent = selectedContact?.name || "Nombre del Contacto";
        dynamicElements.previewContactAddress.textContent = selectedContact?.street_address || selectedContact?.address || '';
        dynamicElements.previewContactAddress.style.display = (selectedContact?.street_address || selectedContact?.address) ? '' : 'none';

        dynamicElements.previewContactEmail.textContent = selectedContact?.email || '';
        dynamicElements.previewContactEmail.style.display = selectedContact?.email ? '' : 'none';

        const phone = selectedContact?.phone || selectedContact?.mobile;
        dynamicElements.previewContactPhone.textContent = phone || '';
        dynamicElements.previewContactPhone.style.display = phone ? '' : 'none';

        dynamicElements.previewDate.textContent = new Date().toLocaleDateString('es-ES');

        let invoiceNumberDisplay = 'NUEVO';
        if (elements.editingInvoiceId.value) {
            const externalIdKey = elements.editingInvoiceId.value;
            const numericId = allInvoices[externalIdKey]?.db_id;
            if (numericId !== undefined && !isNaN(numericId)) {
                invoiceNumberDisplay = String(numericId).padStart(3, '0');
            }
        } else {
            invoiceNumberDisplay = String(nextAvailableInvoiceNumber).padStart(3, '0');
        }
        dynamicElements.previewInvoiceId.textContent = invoiceNumberDisplay;
        recalculateTotal();
    };
    
// ====================================================================================================================
// LÓGICA DE NEGOCIO
// ====================================================================================================================

    const createItemRow = (desc = "Nuevo Ítem", unitPrice = 0.00, qty = 1) => {
        const row = document.createElement('tr');
        const safeDesc = escapeHTML(desc);  
        const safeQty = escapeHTML(qty.toString()); 
        const safeUnitPrice = `$${parseFloat(unitPrice).toFixed(2)}`;
        const safeItemTotal = `$${(unitPrice * qty).toFixed(2)}`;

        row.innerHTML = `
            <td class="p-3 border-b" contenteditable="true">${safeDesc}</td>
            <td class="text-right p-3 item-qty border-b" contenteditable="true">${safeQty}</td>
            <td class="text-right p-3 item-unit-price border-b" contenteditable="true">${safeUnitPrice}</td>
            <td class="text-right p-3 item-total-price border-b">${safeItemTotal}</td>
            <td class="p-3 border-b text-center">
                <button type="button" class="text-[var(--color-secondary)] hover:text-red-600 remove-item-btn font-bold text-lg" title="Remove Item">
                    <i data-lucide="x" class="w-5 h-5"></i>
                </button>
            </td>
        `;
        const removeButton = row.querySelector('.remove-item-btn');
        if (removeButton) {
            removeButton.addEventListener('click', () => {
                row.remove();
                recalculateTotal();
            });
        }
        return row;
    };

    const recalculateTotal = () => {
        if (!dynamicElements.invoiceItemsBody) return;
        let subtotal = 0;
        dynamicElements.invoiceItemsBody.querySelectorAll('tr').forEach(row => {
            const qty = parseInt(row.cells[1].textContent) || 0;
            const unitPrice = parseFloat(row.cells[2].textContent.replace(/[$,]/g, '')) || 0;
            const itemTotal = qty * unitPrice;
            row.cells[3].textContent = `$${itemTotal.toFixed(2)}`;
            subtotal += itemTotal;
        });
        const taxRate = parseFloat(elements.taxRate.value) || 0;
        const taxAmount = subtotal * (taxRate / 100);
        const total = subtotal + taxAmount;
        if (dynamicElements.previewSubtotal) dynamicElements.previewSubtotal.textContent = `$${subtotal.toFixed(2)}`;
        if (dynamicElements.previewTaxRate) dynamicElements.previewTaxRate.textContent = taxRate.toFixed(2);
        if (dynamicElements.previewTaxAmount) dynamicElements.previewTaxAmount.textContent = `$${taxAmount.toFixed(2)}`;
        if (dynamicElements.previewTotal) dynamicElements.previewTotal.textContent = `$${total.toFixed(2)}`;
    };

    const updateDisplay = () => {
        const monthValue = elements.monthFilter ? elements.monthFilter.value : 'all';
        renderTable(monthValue);
    };

    const renderTable = (monthFilterValue) => {
        const filters = {
            term: elements.listSearch.value.toLowerCase(),
            status: elements.listFilterStatus.value
        };

        const filteredData = Object.values(allInvoices).filter(doc => {
            const matchesTerm = doc.cliente.toLowerCase().includes(filters.term);
            const matchesStatus = (filters.status === 'all' || formatStatusText(doc.estado).toLowerCase() === filters.status);
            const currentMonthFilter = monthFilterValue || 'all'; 
            const matchesMonth = (currentMonthFilter === 'all') || (doc.fechaSolicitud.startsWith(currentMonthFilter));
            return matchesTerm && matchesStatus && matchesMonth;
        });
        
        elements.invoicesTableBody.innerHTML = '';
        elements.noInvoicesMsg.classList.toggle('hidden', filteredData.length > 0);
        
        filteredData.forEach(doc => {
            const row = elements.invoicesTableBody.insertRow();
            row.className = 'border-b hover:bg-gray-50';
            const isPaid = doc.estado.toLowerCase() === 'pagada' || doc.estado.toLowerCase() === 'paid';
            
            const displayStatusText = formatStatusText(doc.estado);
            
            row.innerHTML = `
                <td class="py-4 px-6" data-label="FECHA">${escapeHTML(doc.fechaSolicitud)}</td>
                <td class="py-4 px-6" data-label="CLIENTE">${escapeHTML(doc.cliente)}</td>
                <td class="py-4 px-6" data-label="SERVICIO">${escapeHTML(doc.servicio)}</td>
                <td class="py-4 px-6" data-label="MONTO">$${parseFloat(doc.montoFacturado).toFixed(2)}</td>
                <td class="py-4 px-6" data-label="ESTADO">
                    <span class="${getStatusClass(doc.estado)} py-1 px-3 rounded-full text-xs font-bold">${displayStatusText}</span>
                </td>
                <td class="py-4 px-6 text-center actions-cell" data-label="ACCIONES">
                    <div class="flex flex-col sm:flex-row items-center justify-center space-y-2 sm:space-y-0 sm:space-x-3">
                        
                        <button class="text-indigo-600 hover:text-indigo-800 copy-row-link-btn w-full sm:w-auto" data-token="${doc.id}" title="Copiar Enlace Digital">
                            <i data-lucide="link" class="w-5 h-5"></i>
                        </button>

                        ${isPaid ? `
                            <button class="text-green-600 hover:text-green-800 edit-invoice-btn w-full sm:w-auto" data-invoice-id="${doc.id}" title="Descargar/Ver Pagada">
                                <i data-lucide="download" class="w-5 h-5"></i>
                            </button>
                            <span class="text-gray-400 w-full sm:w-auto" title="Factura Pagada">
                                <i data-lucide="check-check" class="w-5 h-5"></i>
                            </span>
                        ` : `
                            <button class="text-gray-500 hover:text-gray-700 change-status-btn w-full sm:w-auto" data-invoice-id="${doc.id}" data-current-status="${doc.estado}" title="Cambiar Estado">
                                <i data-lucide="edit-3" class="w-5 h-5"></i>
                            </button>
                            <button class="text-blue-600 hover:text-blue-800 edit-invoice-btn w-full sm:w-auto" data-invoice-id="${doc.id}" title="Ver/Editar">
                                <i data-lucide="eye" class="w-5 h-5"></i>
                            </button>
                        `}
                        <button class="text-[var(--color-secondary)] hover:text-red-600 delete-invoice-btn w-full sm:w-auto" data-invoice-id="${doc.id}" title="Eliminar">
                            <i data-lucide="trash-2" class="w-5 h-5"></i>
                        </button>
                    </div>
                </td>`;
        });

        if (typeof lucide !== 'undefined') lucide.createIcons();
        setupActionListeners();
        setupQuickLinkListeners();
    };

// ====================================================================================================================
// INTERACCIÓN Y API
// ====================================================================================================================

    const showGeneratorView = (externalId = null) => {
        elements.generatorView.classList.remove('hidden');
        setTimeout(() => { elements.generatorPanel.classList.remove('translate-x-full'); }, 10);
        elements.invoiceContent.innerHTML = invoiceTemplateHTML;
        
        bindDynamicElements();
        resetGeneratorForm();
        applyStatusSeal(null);  
        
        let isPaid = false;
        
        const digitalLinkContainer = document.getElementById('digital-link-container');
        const sidebarQuoteLink = document.getElementById('sidebar-quote-link');
        const sidebarOpenBtn = document.getElementById('sidebar-open-btn');

        if (externalId && allInvoices[externalId]) {
            const invoice = allInvoices[externalId];
            isPaid = invoice.estado.toLowerCase() === 'pagada' || invoice.estado.toLowerCase() === 'paid';
            elements.generatorTitle.textContent = `Editando Factura #${invoice.id.replace('inv-', '')}`;
            elements.editingInvoiceId.value = externalId;
            if (invoice.contact) handleContactSelection(invoice.contact);
            elements.taxRate.value = invoice.taxRate || 0;
            
            dynamicElements.invoiceItemsBody.innerHTML = '';
            invoice.items.forEach(([desc, price, quantity = 1]) => dynamicElements.invoiceItemsBody.appendChild(createItemRow(desc, price, quantity)));
            
            if (invoice.items.length > 0) {
                const firstItemDesc = invoice.items[0][0];
                const matchingService = allServices.find(s => s.id == elements.tipoServicio.value); 
                if (matchingService) elements.tipoServicio.value = matchingService.id;
                else elements.tipoServicio.value = '';
            }
            
            if (digitalLinkContainer) {
                const baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
                const fullLink = `${baseUrl}/invoice-view.php?token=${externalId}`;
                sidebarQuoteLink.value = fullLink;
                sidebarOpenBtn.href = fullLink;
                digitalLinkContainer.classList.remove('hidden');
            }

            applyStatusSeal(invoice.estado);

        } else {
            dynamicElements.invoiceItemsBody.appendChild(createItemRow("Nuevo Ítem", 0.00, 1));  
            elements.generatorTitle.textContent = 'Crear Nueva Factura';
            elements.editingInvoiceId.value = '';
            
            if (digitalLinkContainer) {
                digitalLinkContainer.classList.add('hidden');
                sidebarQuoteLink.value = '';
            }
            
            applyStatusSeal('generated');
        }
        
        const editableContent = elements.invoiceContent.querySelectorAll('[contenteditable="true"]');
        const itemRows = dynamicElements.invoiceItemsBody?.querySelectorAll('tr');
        
        if (isPaid) {
            elements.saveInvoiceBtn.classList.add('hidden');
            editableContent.forEach(el => el.setAttribute('contenteditable', 'false'));
            if (dynamicElements.addItemBtn) dynamicElements.addItemBtn.classList.add('hidden');
            if (itemRows) itemRows.forEach(row => row.querySelector('.remove-item-btn')?.classList.add('hidden'));
            elements.tipoServicio.disabled = true;
            elements.taxRate.disabled = true;
            elements.changeContactBtn.classList.add('hidden');
        } else {
            elements.saveInvoiceBtn.classList.remove('hidden');
            editableContent.forEach(el => el.setAttribute('contenteditable', 'true'));
            if (dynamicElements.addItemBtn) dynamicElements.addItemBtn.classList.remove('hidden');
            if (itemRows) itemRows.forEach(row => row.querySelector('.remove-item-btn')?.classList.remove('hidden'));
            elements.tipoServicio.disabled = false;
            elements.taxRate.disabled = false;
            elements.changeContactBtn.classList.remove('hidden');
        }

        updatePreview();

        if (typeof lucide !== 'undefined') {
            lucide.createIcons({ container: elements.generatorPanel });
        }
    };

    const hideGeneratorView = () => {
        elements.generatorPanel.classList.add('translate-x-full');
        setTimeout(() => { elements.generatorView.classList.add('hidden'); }, 300);
        applyStatusSeal(null);
    };

    const setupActionListeners = () => {
        document.querySelectorAll('.change-status-btn').forEach(button => {
            button.onclick = null;  
            button.addEventListener('click', (event) => {
                const { invoiceId, currentStatus } = event.currentTarget.dataset;
                showStatusModal(invoiceId, currentStatus);
                event.stopPropagation();
            });
        });

        document.querySelectorAll('.edit-invoice-btn').forEach(button => {
            button.onclick = null;  
            button.addEventListener('click', (event) => {
                const { invoiceId } = event.currentTarget.dataset;
                showGeneratorView(invoiceId);
                event.stopPropagation();
            });
        });

        document.querySelectorAll('.delete-invoice-btn').forEach(button => {
            button.onclick = null;  
            button.addEventListener('click', (event) => {
                const { invoiceId } = event.currentTarget.dataset;
                openConfirmDeleteModal(invoiceId, 'factura');
                event.stopPropagation();
            });
        });
    };

    const fetchAndDisplayInvoices = async () => {
        try {
            const response = await fetch(API_URLS.INVOICE_READ);
            const result = await response.json();
            if (result.success) {
                allInvoices = {};
                let currentMaxDbId = 0;
                result.data.forEach(invoice => {
                    invoice.cliente = escapeHTML(invoice.cliente);
                    invoice.servicio = escapeHTML(invoice.servicio);
                    if (invoice.contact) {
                        invoice.contact.name = escapeHTML(invoice.contact.name);
                        invoice.contact.email = escapeHTML(invoice.contact.email);
                        invoice.contact.street_address = escapeHTML(invoice.contact.street_address);
                    }
                    allInvoices[invoice.id] = invoice;
                    if (parseInt(invoice.db_id) > currentMaxDbId) currentMaxDbId = parseInt(invoice.db_id);
                });
                nextAvailableInvoiceNumber = currentMaxDbId + 1;
                updateMonthFilterOptions();
            } else {
                showToast('Error al cargar facturas: ' + (result.message || 'Error desconocido.'), 'error');
            }
        } catch (error) {
            showToast('Error de conexión al cargar facturas.', 'error');
        }
    };
    
    const saveInvoice = async () => {
        if (!selectedContact || selectedContact.type !== 'client') {
            showToast("Por favor, selecciona un cliente.", 'warning');
            return;
        }

        const itemsData = Array.from(dynamicElements.invoiceItemsBody.querySelectorAll('tr')).map(row => {
            const [desc, qty, unitPrice] = [escapeHTML(row.cells[0].textContent), parseInt(row.cells[1].textContent) || 1, parseFloat(row.cells[2].textContent.replace(/[$,]/g, '')) || 0];
            return [desc, unitPrice, qty];
        }).filter(([desc, unitPrice, qty]) => desc.trim() !== '' && (unitPrice > 0 || qty > 0) && desc.trim() !== 'Nuevo Ítem');

        if (itemsData.length === 0) {
            showToast("Por favor, agrega al menos un ítem válido.", 'warning');
            return;
        }

        const isEditing = elements.editingInvoiceId.value !== '';
        
        const currentDBStatus = isEditing 
            ? allInvoices[elements.editingInvoiceId.value]?.estado.toLowerCase() || 'generated'
            : 'generated';
            
        // Asegura que el estado enviado al servidor sea la versión en inglés
        const displayStatusKey = STATUS_MAP[currentDBStatus];
        const statusToSend = SPANISH_TO_ENGLISH[displayStatusKey] || currentDBStatus; 

        const invoiceData = {
            id: isEditing ? allInvoices[elements.editingInvoiceId.value]?.db_id : null,
            invoice_date: new Date().toISOString().split('T')[0],
            status: statusToSend,
            tax_rate: parseFloat(elements.taxRate.value) || 0,
            items: itemsData,
            client_id: selectedContact.id,
            lead_id: null,
            user_id: USER_ID, 
            csrf_token: CSRF_TOKEN
        };

        const apiUrl = isEditing ? API_URLS.INVOICE_UPDATE : API_URLS.INVOICE_CREATE;

        try {
            const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(invoiceData) });
            const result = await response.json();
            if (result.success) {
                hideGeneratorView();

                let externalId = invoiceData.id ? elements.editingInvoiceId.value : result.external_id;
                const baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
                const fullLink = `${baseUrl}/invoice-view.php?token=${externalId}`;

                const successLinkInput = document.getElementById('success-quote-link');
                const successOpenBtn = document.getElementById('success-open-btn');
                
                if (successLinkInput && successOpenBtn) {
                    successLinkInput.value = fullLink;
                    successOpenBtn.href = fullLink;
                    openModal('invoiceSuccessModal');
                } else {
                    showToast(`Factura guardada correctamente.`, 'success');
                    location.reload();
                }

            } else {
                showToast(`Error al guardar: ${result.message}`, 'error');
            }
        } catch (error) {
            console.error('Error al guardar:', error);
            showToast('Error de conexión al guardar.', 'error');
        }
    };

    const executeDeleteInvoice = async (externalId) => {
        const invoiceToDelete = allInvoices[externalId];
        if (!invoiceToDelete || !invoiceToDelete.db_id) {
            showToast('Error: ID de factura no encontrado.', 'error');
            return;
        }

        const payload = { id: invoiceToDelete.db_id, csrf_token: CSRF_TOKEN };

        try {
            const response = await fetch(API_URLS.INVOICE_DELETE, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
            const result = await response.json();
            if (result.success) {
                showToast('Factura eliminada con éxito.', 'success');
                closeModal('confirmDeleteModal');
                location.reload();
            } else {
                showToast(`Error al eliminar: ${result.message}`, 'error');
            }
        } catch (error) {
            console.error('Error al eliminar:', error);
            showToast('Error de conexión al eliminar.', 'error');
        }
    };

    const updateInvoiceStatus = async (externalId, newStatus) => {
        const invoice = allInvoices[externalId];
        if (!invoice || !invoice.db_id) {
            showToast('Error: Datos de la factura no encontrados.', 'error');
            return;
        }

        // newStatus ya viene en inglés desde el valor del select del modal
        const payload = { 
            id: invoice.db_id, 
            status: newStatus, 
            user_id: USER_ID, 
            csrf_token: CSRF_TOKEN 
        };

        try {
            const response = await fetch(API_URLS.INVOICE_STATUS_UPDATE, { 
                method: 'POST', 
                headers: { 'Content-Type': 'application/json' }, 
                body: JSON.stringify(payload) 
            });
            const result = await response.json();
            if (result.success) {
                closeModal('status-modal-overlay');
                showToast(`Estado de la factura actualizado.`, 'success');
                location.reload();
            } else {
                showToast(`Error al actualizar estado: ${result.message}`, 'error');
            }
        } catch (error) {
            console.error('Error de conexión al actualizar estado:', error);
            showToast('Error de conexión al actualizar el estado.', 'error');
        }
    };

    const showStatusModal = (externalId, currentStatusFromDB) => {
        elements.modalInvoiceId.value = externalId;
        
        elements.modalStatusSelect.innerHTML = MASTER_STATUSES_LIST.map(serverValue => {
            const displayValue = STATUS_MAP[serverValue];
            
            // Lógica de selección: compara el valor de la DB (currentStatusFromDB) con la clave del mapa (serverValue)
            const isSelected = (serverValue.toLowerCase() === currentStatusFromDB.toLowerCase()); 

            return `
                <option value="${serverValue}" ${isSelected ? 'selected' : ''}>${displayValue}</option>
            `;
        }).join('');
        
        openModal('status-modal-overlay');
    };

    const setupSearch = (inputEl, suggestionEl) => {
        let searchTimeout;
        inputEl.addEventListener('input', () => {
            clearTimeout(searchTimeout);
            const searchTerm = inputEl.value.toLowerCase();
            suggestionEl.innerHTML = '';
            if (!searchTerm || searchTerm.length < 2) { 
                suggestionEl.classList.add('hidden'); 
                return; 
            }
            searchTimeout = setTimeout(() => {
                const matches = allClients.filter(c => 
                    (c.name?.toLowerCase().includes(searchTerm)) || 
                    (c.email?.toLowerCase().includes(searchTerm))
                );
                if (matches.length > 0) {
                    matches.forEach(contact => {
                        const div = document.createElement('div');
                        div.className = 'p-2 hover:bg-gray-100 cursor-pointer text-sm border-b last:border-b-0';
                        div.textContent = `${contact.name} (${contact.email || 'Sin email'})`; 
                        div.dataset.clientId = contact.id;
                        
                        div.addEventListener('mousedown', (e) => {
                            e.preventDefault();
                            handleContactSelection(contact);
                            suggestionEl.classList.add('hidden');
                        });
                        suggestionEl.appendChild(div);
                    });
                    suggestionEl.classList.remove('hidden');
                } else {
                    suggestionEl.classList.add('hidden');
                }
            }, 300);
        });
        inputEl.addEventListener('blur', () => {
            setTimeout(() => { if (!suggestionEl.matches(':hover')) suggestionEl.classList.add('hidden'); }, 200);
        });
    };

    const populateServiceDropdown = () => {
        const { tipoServicio } = elements;
        tipoServicio.innerHTML = '<option value="">-- Selecciona Un Servicio --</option>';
        const servicesByCategory = allServices.reduce((acc, service) => {
            const category = escapeHTML(service.category || 'Sin Categoría');
            if (!acc[category]) acc[category] = [];
            acc[category].push(service);
            return acc;
        }, {});

        for (const category in servicesByCategory) {
            const optgroup = document.createElement('optgroup');
            optgroup.label = category;
            servicesByCategory[category].forEach(service => {
                const option = new Option(`${escapeHTML(service.name)} ($${parseFloat(service.price).toFixed(2)})`, service.id);
                optgroup.appendChild(option);
            });
            tipoServicio.appendChild(optgroup);
        }
    };

    const updateMonthFilterOptions = () => {
        const months = [...new Set(Object.values(allInvoices).map(q => q.fechaSolicitud.substring(0, 7)))].sort().reverse();
        const currentMonthYear = new Date().toISOString().substring(0, 7);
        
        elements.monthFilter.innerHTML = `<option value="all">TODOS LOS MESES</option>` + months.map(m => {
            const date = new Date(`${m}-02T12:00:00`);
            const monthName = date.toLocaleString('es-ES', { month: 'long', timeZone: 'UTC' });
            return `<option value="${m}">${monthName.charAt(0).toUpperCase() + monthName.slice(1).toUpperCase()} ${date.getUTCFullYear()}</option>`;
        }).join('');
        
        if (months.includes(currentMonthYear)) {
            elements.monthFilter.value = currentMonthYear;
        } else if (months.length > 0) {
            elements.monthFilter.value = months[0];
        } else {
            elements.monthFilter.value = 'all';
        }
    };


    const generatePDF = () => {
        showToast('Generando PDF...', 'info');
        
        if (elements.invoiceStatusSealContainer && !elements.invoiceStatusSealContainer.classList.contains('hidden')) {
            elements.invoiceStatusSealContainer.classList.remove('opacity-10');
            elements.invoiceStatusSealContainer.classList.add('opacity-40');
        }
        
        const invoiceElement = document.getElementById('pdf-preview');
        const addItemBtn = invoiceElement?.querySelector('#addItemBtn');
        const removeBtns = invoiceElement?.querySelectorAll('.remove-item-btn');
        
        const togglePdfStyles = (hide = true) => {
            if (addItemBtn) addItemBtn.style.display = hide ? 'none' : '';
            if (removeBtns) removeBtns.forEach(btn => btn.style.display = hide ? 'none' : '');
            const invoiceItemsBody = invoiceElement?.querySelector('#invoice-items');
            if (invoiceItemsBody) invoiceItemsBody.style.marginBottom = hide ? '20px' : '';
            
            if (invoiceElement) {
                invoiceElement.style.width = hide ? '816px' : '';
                invoiceElement.style.margin = hide ? '0 auto' : '';
                invoiceElement.style.padding = hide ? '32px' : '';
                invoiceElement.style.boxSizing = hide ? 'border-box' : '';
            }
            
            if (elements.invoiceContent) {
                elements.invoiceContent.style.margin = hide ? '0 auto' : '';
                elements.invoiceContent.style.maxWidth = hide ? '650px' : '';
            }
        };
        
        togglePdfStyles(true);

        html2canvas(invoiceElement, { scale: 2, useCORS: true, width: 816 }).then(canvas => {
            togglePdfStyles(false);
            
            if (elements.invoiceStatusSealContainer) {
                elements.invoiceStatusSealContainer.classList.remove('opacity-40');
                elements.invoiceStatusSealContainer.classList.add('opacity-10');
            }
            
            const imgData = canvas.toDataURL('image/png');
            const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'letter' });
            const pdfWidth = pdf.internal.pageSize.getWidth();
            const pdfHeight = pdf.internal.pageSize.getHeight();
            const imgHeight = (canvas.height * pdfWidth) / canvas.width;
            let heightLeft = imgHeight;
            let position = 0;

            pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight);
            heightLeft -= pdfHeight;

            while (heightLeft >= 0) {
                position = heightLeft - imgHeight;
                pdf.addPage();
                pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight);
            }

            pdf.save(`Factura-${dynamicElements.previewInvoiceId.textContent}-${dynamicElements.previewContactName.textContent.replace(/\s+/g, '_')}.pdf`);
            showToast('PDF generado.', 'success');
        }).catch(err => {
            togglePdfStyles(false);
            if (elements.invoiceStatusSealContainer) {
                elements.invoiceStatusSealContainer.classList.remove('opacity-40');
                elements.invoiceStatusSealContainer.classList.add('opacity-10');
            }
            console.error("Error al generar PDF:", err);
            showToast('Error al generar el PDF de la factura.', 'error');
        });
    };
    
// ====================================================================================================================
// INICIALIZACIÓN (INIT)
// ====================================================================================================================

        (async function init() {
            
            // Listeners de UI
            document.getElementById('mobile-menu-button')?.addEventListener('click', () => { document.getElementById('sidebar').classList.toggle('-translate-x-full'); document.getElementById('sidebar-overlay').classList.toggle('hidden'); });
            document.getElementById('sidebar-overlay')?.addEventListener('click', () => { document.getElementById('sidebar').classList.add('-translate-x-full'); document.getElementById('sidebar-overlay').classList.add('hidden'); });
            if (document.getElementById('contact_phone')) IMask(document.getElementById('contact_phone'), { mask: '(000) 000-0000' });

            // Carga de datos iniciales
            const [clientsResponse, servicesResponse] = await Promise.all([
                fetch(API_URLS.CLIENTS_READ),
                fetch(API_URLS.SERVICES_READ)
            ]);
            const [clientsResult, servicesResult] = await Promise.all([clientsResponse.json(), servicesResponse.json()]);

            if (clientsResult.success) {  
                allClients = clientsResult.data.map(c => ({...c, name: escapeHTML(c.name), email: escapeHTML(c.email), street_address: escapeHTML(c.street_address)}));
                setupSearch(elements.clientSearch, elements.clientSuggestions);  
            } else { showToast('Error al cargar clientes: ' + (clientsResult.message || 'Error desconocido.'), 'error'); }

            if (servicesResult.success) { allServices = servicesResult.data; populateServiceDropdown(); }
            else { showToast('Error al cargar servicios: ' + (servicesResult.message || 'Error desconocido.'), 'error'); }

            await fetchAndDisplayInvoices();

            if (elements.listFilterStatus) {
                elements.listFilterStatus.innerHTML = '<option value="all">TODOS LOS ESTADOS</option>';
                // El filtro utiliza las claves en español para filtrar en JS
                Object.values(STATUS_MAP).filter((v, i, a) => a.indexOf(v) === i).forEach(s => elements.listFilterStatus.add(new Option(s, s.toLowerCase())));
            }
            
            updateDisplay();

            // Event Listeners principales de la página
            [elements.listSearch, elements.listFilterStatus].forEach(el => el?.addEventListener('input', updateDisplay));
            elements.monthFilter?.addEventListener('change', updateDisplay);
            elements.showGeneratorBtn?.addEventListener('click', () => showGeneratorView());
            elements.backToListBtn?.addEventListener('click', hideGeneratorView);
            elements.generatorOverlay?.addEventListener('click', hideGeneratorView);
            elements.saveInvoiceBtn?.addEventListener('click', saveInvoice);
            elements.downloadPdfBtn?.addEventListener('click', generatePDF);
            elements.changeContactBtn?.addEventListener('click', () => {
                resetGeneratorForm();
                dynamicElements.invoiceItemsBody.appendChild(createItemRow("Nuevo Ítem", 0.00, 1));
                if (typeof lucide !== 'undefined') { lucide.createIcons(); }
            });
            elements.taxRate?.addEventListener('input', recalculateTotal);
            elements.tipoServicio?.addEventListener('change', () => {
                const selectedServiceId = elements.tipoServicio.value;
                if (selectedServiceId) {
                    const service = allServices.find(s => s.id == selectedServiceId);
                    if (service && dynamicElements.invoiceItemsBody) {
                        const firstRow = dynamicElements.invoiceItemsBody.querySelector('tr');
                        const isDefaultRow = firstRow && firstRow.cells[0].textContent.trim() === 'Nuevo Ítem' && parseFloat(firstRow.cells[2].textContent.replace(/[$,]/g, '')) === 0;

                        if (isDefaultRow) firstRow.remove();

                        dynamicElements.invoiceItemsBody.appendChild(createItemRow(service.name, service.price, 1));
                        recalculateTotal();
                        if (typeof lucide !== 'undefined') lucide.createIcons();
                    }
                }
            });

            // Listeners para Modals
            document.getElementById('modal-cancel-btn')?.addEventListener('click', () => closeModal('status-modal-overlay'));
            document.getElementById('status-modal-overlay')?.addEventListener('click', (event) => { if (event.target === document.getElementById('status-modal-overlay')) closeModal('status-modal-overlay'); });
            document.getElementById('modal-save-status-btn')?.addEventListener('click', () => {
                const externalId = elements.modalInvoiceId.value;
                const newStatus = elements.modalStatusSelect.value; // Ya está en inglés
                updateInvoiceStatus(externalId, newStatus);
            });
            document.getElementById('confirm-delete-button')?.addEventListener('click', function() { executeDeleteInvoice(this.dataset.itemId); });
            document.getElementById('cancel-delete-btn')?.addEventListener('click', () => closeModal('confirmDeleteModal'));

            // Listeners para el botón cerrar del modal de éxito (Recarga la página)
            const closeSuccessBtn = document.getElementById('close-success-modal-btn');
            if (closeSuccessBtn) {
                closeSuccessBtn.addEventListener('click', () => {
                    location.reload();
                });
            }

            // Listener para copiar link del modal de éxito
            const successCopyBtn = document.getElementById('success-copy-btn');
            if (successCopyBtn) {
                successCopyBtn.addEventListener('click', () => {
                    const linkInput = document.getElementById('success-quote-link');
                    linkInput.select();
                    linkInput.setSelectionRange(0, 99999);
                    navigator.clipboard.writeText(linkInput.value).then(() => {
                        if (typeof showToast === 'function') showToast("Enlace de factura copiado", 'success');
                    });
                });
            }

            // Listener para copiar link del panel lateral
            const sidebarCopyBtn = document.getElementById('sidebar-copy-btn');
            if (sidebarCopyBtn) {
                sidebarCopyBtn.addEventListener('click', () => {
                    const linkInput = document.getElementById('sidebar-quote-link');
                    linkInput.select();
                    linkInput.setSelectionRange(0, 99999);
                    navigator.clipboard.writeText(linkInput.value).then(() => {
                        if (typeof showToast === 'function') showToast("Enlace de factura copiado", 'success');
                    });
                });
            }

            if (typeof lucide !== 'undefined') lucide.createIcons();
        })();
    });
</script>
<script src="files/toast.js"></script>
</body>
</html>