<?php
// Incluir el archivo de conexión a la base de datos con la ruta correcta.
include_once 'db/db_connection.php'; // Ruta corregida

ob_start();
error_reporting(E_ALL); // Habilitado para depuración
ini_set('display_errors', 1); // Habilitado para depuración

$db_error_message = null; // Variable para capturar errores de DB en PHP

try {
    // Intentar leer la única fila de configuración (con ID 1)
    $stmt = $pdo->query("SELECT * FROM website_config WHERE id = 1"); //
    $config = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($config) {
        // Decodificar los campos JSON
        $config['gallery_images'] = json_decode($config['gallery_images'] ?? '[]', true);
        $config['cities_operated'] = json_decode($config['cities_operated'] ?? '[]', true);
        $config['weekly_schedule'] = json_decode($config['weekly_schedule'] ?? '[]', true); // Se asume un array de objetos para el horario semanal
        $config['blocked_dates'] = json_decode($config['blocked_dates'] ?? '[]', true);
        $config['enable_booking'] = (bool)$config['enable_booking']; // Convertir a booleano

        // Asignar variables PHP para usar en el HTML de la factura
        $company_logo_url = htmlspecialchars($config['logo_url'] ?? 'img/placeholder-logo.png'); // Placeholder si no hay logo
        $company_name_from_db = htmlspecialchars($config['company_name'] ?? 'Nombre de la Empresa');
        $contact_name_from_db = htmlspecialchars($config['contact_name'] ?? 'Nombre de Contacto');
        $contact_email_from_db = htmlspecialchars($config['email'] ?? 'correo@ejemplo.com');
        $contact_phone_from_db = htmlspecialchars($config['phone_primary'] ?? 'N/A');

        // No es necesario $response_data si solo se usa para pasar a JS en el mismo archivo
    } else {
        // Si no existe la fila, usar valores por defecto
        $company_logo_url = 'img/placeholder-logo.png';
        $company_name_from_db = 'Nombre de la Empresa';
        $contact_name_from_db = 'Nombre de Contacto';
        $contact_email_from_db = 'correo@ejemplo.com';
        $contact_phone_from_db = 'N/A';
        $db_error_message = 'No se encontró la configuración inicial. Se usarán valores por defecto.';
    }

} catch (PDOException $e) {
    error_log("Error PDO al cargar configuración web: " . $e->getMessage());
    $company_logo_url = 'img/placeholder-logo.png';
    $company_name_from_db = 'Nombre de la Empresa';
    $contact_name_from_db = 'Nombre de Contacto';
    $contact_email_from_db = 'correo@ejemplo.com';
    $contact_phone_from_db = 'N/A';
    $db_error_message = 'Error de Base de Datos al cargar configuración: ' . $e->getMessage();
} catch (Exception $e) {
    error_log("General Error al cargar configuración web: " . $e->getMessage());
    $company_logo_url = 'img/placeholder-logo.png';
    $company_name_from_db = 'Nombre de la Empresa';
    $contact_name_from_db = 'Nombre de Contacto';
    $contact_email_from_db = 'correo@ejemplo.com';
    $contact_phone_from_db = 'N/A';
    $db_error_message = 'Error inesperado al cargar configuración: ' . $e->getMessage();
}

ob_end_clean();
// Eliminar el bloque de $_SESSION['notification'] ya que JS Toast lo maneja
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LocalCRM ToolKit Dashboard | Facturas | OrozDesign Multiemdia</title>
    <meta name="description" content="Genera facturas en LocalCRM: crea, ajusta y administra tus cobros de servicios con profesionalismo">
    <meta name="robots" content="noindex, nofollow">

    <link rel="icon" type="image/png" href="img/favicon.png">
    <link rel="apple-touch-icon" href="img/apple-touch-icon.png">

    <?php include 'files/gtm-head.php'; ?>
    
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Barlow:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />

    <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>

    <link rel="stylesheet" href="style.css">
    <script src="files/header-manager.js"></script>
    <style>
        .interactive-module { background-color: #f7fafc; padding: 2rem; border-radius: 0.75rem; border: 1px solid #e2e8f0; }
        .stat-card { background-color: white; padding: 1.5rem; border-radius: 0.75rem; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); border-left: 5px solid #FFC107; display: flex; align-items: center; gap: 1rem; }
        .stat-card .icon { color: #FFC107; }
        .stat-card .value { color: #98012E; font-weight: 800; font-size: 2.5rem; line-height: 1; }
        .stat-card .title { font-weight: 700; text-transform: uppercase; color: #4A5568; }
        .stat-card .subtitle { font-size: 0.8rem; text-transform: uppercase; color: #A0AEC0; }
        /* Clases para el ícono de búsqueda en los inputs */
        .input-with-icon { position: relative; }
        .input-with-icon input { padding-left: 2.5rem; } /* Ajusta el padding para el ícono */
        .input-with-icon .search-icon {
            position: absolute;
            left: 0.75rem;
            top: 50%;
            transform: translateY(-50%);
            color: #A0AEC0;
            pointer-events: none; /* Permite clics a través del ícono al input */
        }
        /* Estilos para los botones de acción de estado (los de la implementación anterior, ya no se usan así) */
        .status-action-btn {
            @apply px-2 py-1 rounded-md text-xs font-semibold uppercase transition-colors duration-200;
        }
        .status-action-btn.send { @apply bg-blue-500 text-white hover:bg-blue-600; }
        .status-action-btn.approve { @apply bg-green-500 text-white hover:bg-green-600; }
        .status-action-btn.reject { @apply bg-red-500 text-white hover:bg-red-600; }
        .status-action-btn:disabled {
            @apply bg-gray-300 text-gray-500 cursor-not-allowed;
        }

        /* Estilos para el Modal de cambio de estado */
        .status-modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
            visibility: hidden;
            opacity: 0;
            transition: visibility 0s, opacity 0.3s ease-in-out;
        }

        .status-modal-overlay.active {
            visibility: visible;
            opacity: 1;
        }

        .status-modal {
            background-color: white;
            padding: 2rem;
            border-radius: 0.75rem;
            box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.1); /* Adjusted shadow */
            width: 90%;
            max-width: 400px;
            transform: translateY(-20px);
            transition: transform 0.3s ease-in-out;
        }

        .status-modal-overlay.active .status-modal {
            transform: translateY(0);
        }

        /* === NUEVAS REGLAS PARA TABLAS RESPONSIVAS === */
        @media (max-width: 767px) {
            .responsive-table-stack tbody,
            .responsive-table-stack tr,
            .responsive-table-stack td {
                display: block;
                width: 100%;
            }

            .responsive-table-stack thead {
                display: none; /* Oculta el encabezado de la tabla original */
            }

            .responsive-table-stack tr {
                margin-bottom: 1rem; /* Espacio entre las "tarjetas" de fila */
                border: 1px solid #e2e8f0;
                border-radius: 0.5rem;
                padding: 0.5rem;
                background-color: white;
                box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
            }

            .responsive-table-stack td {
                text-align: right !important; /* Alinea el valor a la derecha */
                padding-left: 50% !important; /* Deja espacio para la etiqueta */
                position: relative;
                border-bottom: 1px solid #edf2f7; /* Separador entre campos */
                padding-top: 0.75rem;
                padding-bottom: 0.75rem;
                white-space: normal; /* Permite que el texto se ajuste */
                word-break: break-word; /* Rompe palabras largas */
            }

            .responsive-table-stack td:last-child {
                border-bottom: 0; /* No hay borde inferior en el último campo */
            }

            /* Etiqueta del campo (header) */
            .responsive-table-stack td::before {
                content: attr(data-label); /* Usa el atributo data-label como contenido */
                position: absolute;
                left: 0.75rem;
                width: calc(50% - 1.5rem); /* Ocupa la mitad izquierda */
                padding-right: 1rem;
                white-space: nowrap; /* Evita que la etiqueta se rompa */
                text-align: left;
                font-weight: bold;
                text-transform: uppercase;
                color: #4a5568;
                flex-shrink: 0;
            }

            /* Ajustes para celdas de acciones/botones */
            .responsive-table-stack td.actions-cell {
                text-align: center !important;
                padding-left: 0 !important;
                display: flex;
                flex-direction: column; /* Apila los botones verticalmente */
                justify-content: center;
                align-items: center;
                gap: 0.75rem; /* Espacio entre botones */
                min-height: 48px; /* Altura mínima para la fila de botones */
                flex-wrap: wrap; /* Permite que los botones se envuelvan si hay muchos */
            }

            .responsive-table-stack td.actions-cell::before {
                content: none; /* No mostrar etiqueta para celdas de acciones */
            }

            /* Asegurar que los botones dentro de celdas de acción se apilen si es necesario */
            .responsive-table-stack td.actions-cell button {
                width: 100%; /* Toma todo el ancho disponible */
                flex-grow: 0; /* No permite que crezcan, solo que tomen el ancho */
                min-width: 80px; /* Asegura un tamaño mínimo para el botón */
            }
        }
        /* === FIN NUEVAS REGLAS === */
    </style>
</head>
<body data-page-title="GESTIÓN DE FACTURAS"
      data-page-subtitle="CREA, EDITA Y ADMINISTRA TUS COBROS"
      data-page-icon="receipt"
      class="bg-gray-50">

    <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-75 z-30 hidden md:hidden"></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-primary)]">
            <i data-lucide="users" class="w-12 h-12 text-gray-700"></i>
            <div>
                <h3 class="text-lg font-extrabold text-gray-500 mb-1">FACTURAS DE CLIENTES</h3>
                <p id="stats-clients-count" class="text-5xl font-bold text-[var(--color-secondary)]">0</p>
                <p class="text-sm text-gray-400 mt-1">EN EL MES SECCIONADO</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-gray-700"></i>
            <div>
                <h3 class="text-lg font-extrabold text-gray-500 mb-1">VALOR TOTAL FACTURADO</h3>
                <p id="stats-month-total" class="text-5xl font-bold text-[var(--color-secondary)]">$0</p>
                <p class="text-sm text-gray-400 mt-1">DEL MES SECCIONADO</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-secondary)]">
            <i data-lucide="bell" class="w-12 h-12 text-gray-700"></i>
            <div>
                <h3 class="text-lg font-extrabold text-gray-500 mb-1">FACTURAS PENDIENTES</h3>
                <p id="stats-pending-count" class="text-5xl font-bold text-[var(--color-secondary)]">0</p>
                <p class="text-sm text-gray-400 mt-1">QUE SE VENCERAN PRONTO</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="receipt" class="w-7 h-7 text-[var(--color-primary)]"></i> TODAS LAS FACTURAS</h3>
                        <button id="show-generator-btn" class="btn-primary py-2 px-4 rounded-lg flex items-center justify-center w-full md:w-auto uppercase"><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">
                <h1 id="generator-title" class="text-3xl font-black text-gray-800 text-center uppercase">Crear Factura</h1>
                <input type="hidden" id="editing-invoice-id">

                <div class="space-y-4">
                    <h2 class="text-lg font-black text-[var(--color-primary)] flex items-center gap-2 uppercase"><i data-lucide="user-check"></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-lg font-black text-[var(--color-primary)] flex items-center gap-2 uppercase"><i data-lucide="clipboard-list"></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-lg font-black text-[var(--color-primary)] flex items-center gap-2 uppercase"><i data-lucide="percent"></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 class="flex flex-col space-y-3 pt-4"> <button id="save-invoice-btn" class="btn-secondary w-full p-3 rounded-lg text-lg uppercase font-black flex items-center justify-center"><i data-lucide="save" class="w-6 h-6 mr-2"></i> Guardar Cambios</button>
                    <button id="download-pdf-btn" class="btn-primary w-full p-3 rounded-lg text-lg uppercase font-black flex items-center justify-center"><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"><div id="invoice-content"></div></div>
            </div>
        </div>
    </div>
</section>

<div id="status-modal-overlay" class="status-modal-overlay">
    <div id="status-modal" class="status-modal">
        <h3 class="text-xl font-bold mb-4 text-gray-800">CAMBIAR ESTADO DE LA FACTURA</h3>
        <input type="hidden" id="modal-invoice-id">
        <div class="mb-4">
            <label for="modal-status-select" class="block text-gray-700 text-sm font-semibold mb-2">Selecciona Un Nuevo Estado:</label>
            <select id="modal-status-select" class="w-full p-2.5 border border-gray-300 rounded-lg bg-white">
                </select>
        </div>
        <div class="flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3"> <button id="modal-cancel-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg font-semibold w-full sm:w-auto">CANCELAR</button>
            <button id="modal-save-status-btn" class="btn-primary px-4 py-2 rounded-lg font-semibold w-full sm:w-auto">GUARDAR</button>
        </div>
    </div>
</div>

<div id="confirmDeleteModal" class="fixed inset-0 bg-gray-900 bg-opacity-75 flex items-center justify-center hidden z-50">
    <div class="bg-white p-8 rounded-xl shadow-2xl w-full max-w-sm m-4 transform transition-all duration-300 scale-95 opacity-0 text-center">
        <div class="flex justify-center mb-4">
            <i data-lucide="alert-triangle" class="w-16 h-16 text-red-500"></i>
        </div>
        <h3 class="text-2xl font-bold text-[var(--color-primary)] mb-4 uppercase">CONFIRMAR ELIMINACIÓN</h3>
        <p class="text-gray-700 mb-6 uppercase">¿ESTÁS SEGURO DE QUE DESEAS ELIMINAR ESTA <span id="confirm-item-type" class="font-semibold">ELEMENTO</span>? ESTA ACCIÓN NO SE PUEDE DESHACER.</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" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-4 rounded-lg uppercase w-full sm:w-auto" onclick="closeModal('confirmDeleteModal')">CANCELAR</button>
            <button type="button" class="btn-secondary font-bold py-2 px-4 rounded-lg uppercase w-full sm:w-auto" id="confirm-delete-button">CONFIRMAR</button>
        </div>
    </div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
    if (window.jspdf) { window.jsPDF = window.jspdf.jsPDF; }

    let allClients = [];
    let allServices = [];
    let allInvoices = {}; // Cambiado de allEstimates a allInvoices
    let nextAvailableInvoiceNumber = 1; // Cambiado de EstimateNumber a InvoiceNumber

    // MODIFICADO: invoiceTemplateHTML usa las variables PHP y reemplaza "ESTIMATE" por "INVOICE"
    const invoiceTemplateHTML = `<div class="flex justify-between items-start mb-10"><div><img src="<?php echo $company_logo_url; ?>" alt="Logo" class="h-16 mb-4"><h2 class="text-2xl font-black text-gray-800"><?php echo $company_name_from_db; ?></h2><p class="text-gray-600"><?php echo $contact_name_from_db; ?></p><p class="text-gray-600"><?php echo $contact_email_from_db; ?></p><p class="text-gray-600"><?php echo $contact_phone_from_db; ?></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"><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-yellow-300 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>`; // Cambiado el texto de los términos.

    const elements = {
        generatorView: document.getElementById('generator-view-section'),
        generatorPanel: document.getElementById('generator-panel'),
        generatorOverlay: document.getElementById('generator-overlay'),
        showGeneratorBtn: document.getElementById('show-generator-btn'),
        saveInvoiceBtn: document.getElementById('save-invoice-btn'), // Cambiado de saveQuoteBtn
        downloadPdfBtn: document.getElementById('download-pdf-btn'),
        backToListBtn: document.getElementById('back-to-list-btn'),
        invoicesTableBody: document.getElementById('invoicesTableBody'), // Cambiado de estimadosTableBody
        noInvoicesMsg: document.getElementById('no-invoices-msg'), // Cambiado de noEstimadosMsg
        listSearch: document.getElementById('list-search'),
        monthFilter: document.getElementById('month-filter'),
        // Eliminado listFilterContactType
        listFilterStatus: document.getElementById('list-filter-status'),
        generatorTitle: document.getElementById('generator-title'),
        editingInvoiceId: document.getElementById('editing-invoice-id'), // Cambiado de editingQuoteId
        clientSearch: document.getElementById('clientSearch'),
        clientSuggestions: document.getElementById('client-suggestions'),
        // Eliminado prospectSearch y prospectSuggestions
        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'), // Cambiado de quoteContent
        // Eliminado statsProspectsCount
        statsClientsCount: document.getElementById('stats-clients-count'),
        statsMonthTotal: document.getElementById('stats-month-total'),
        statsPendingCount: document.getElementById('stats-pending-count'), // Nuevo para facturas pendientes

        // Status Modal elements
        statusModalOverlay: document.getElementById('status-modal-overlay'),
        statusModal: document.getElementById('status-modal'),
        modalInvoiceId: document.getElementById('modal-invoice-id'), // Cambiado de modalEstimateId
        modalStatusSelect: document.getElementById('modal-status-select'),
        modalCancelBtn: document.getElementById('modal-cancel-btn'),
        modalSaveStatusBtn: document.getElementById('modal-save-status-btn'),

        // NUEVO: Delete Confirmation Modal elements
        confirmDeleteModal: document.getElementById('confirmDeleteModal'),
        confirmDeleteButton: document.getElementById('confirm-delete-button'),
        confirmItemTypeSpan: document.getElementById('confirm-item-type')
    };
    let dynamicElements = {};
    let selectedContact = null; // Will store {id, name, email, address, phone, mobile, type}

    const showGeneratorView = (externalId = null) => {
        elements.generatorView.classList.remove('hidden');
        setTimeout(() => { elements.generatorPanel.classList.remove('translate-x-full'); }, 10);
        elements.invoiceContent.innerHTML = invoiceTemplateHTML; // Cambiado a invoiceContent
        lucide.createIcons(); // Recarga los íconos para el nuevo HTML
        bindDynamicElements();
        resetGeneratorForm();

        if (externalId && allInvoices[externalId]) { // Cambiado de allEstimates
            const invoice = allInvoices[externalId]; // Cambiado de estimate
            elements.generatorTitle.textContent = `Editando Factura #${invoice.id.replace('inv-', '')}`; // Cambiado el prefijo
            elements.editingInvoiceId.value = externalId; // Store the external_id

            // Handle contact selection
            if (invoice.contact) {
                handleContactSelection(invoice.contact);
            }

            elements.taxRate.value = invoice.taxRate || 0;

            dynamicElements.invoiceItemsBody.innerHTML = ''; // Cambiado de quoteItemsBody
            // items are [description, price, quantity]
            invoice.items.forEach(([desc, price, quantity = 1]) => dynamicElements.invoiceItemsBody.appendChild(createItemRow(desc, price, quantity))); // Cambiado de quoteItemsBody

            // Set the "Tipo de Servicio" dropdown if the first item matches
            if (invoice.items.length > 0) {
                const firstItemDesc = invoice.items[0][0];
                const matchingService = allServices.find(s => s.name === firstItemDesc);
                if (matchingService) {
                    elements.tipoServicio.value = matchingService.id; // Set by service ID
                } else {
                    elements.tipoServicio.value = ''; // Reset if not found
                }
            }
            recalculateTotal(); // Recalcula al cargar la factura
        } else {
            elements.generatorTitle.textContent = 'Crear Nueva Factura';
            elements.editingInvoiceId.value = '';
            // dynamicElements.invoiceItemsBody.appendChild(createItemRow('Nuevo Servicio', 0, 1)); // This line was removed as per previous instruction
        }
        updatePreview();
    };

    const hideGeneratorView = () => {
        elements.generatorPanel.classList.add('translate-x-full');
        // Eliminado la recarga aquí, ahora se hace después de guardar/eliminar/actualizar estado
        // setTimeout(() => { elements.generatorView.classList.add('hidden'); fetchAndDisplayInvoices(); }, 300); // Cambiado a fetchAndDisplayInvoices
        setTimeout(() => { elements.generatorView.classList.add('hidden'); }, 300);
    };

    const bindDynamicElements = () => {
        dynamicElements = {
            invoiceItemsBody: document.getElementById('invoice-items'), // Cambiado de quoteItemsBody
            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'), // Cambiado de previewQuoteId
            previewSubtotal: document.getElementById('previewSubtotal'),
            previewTaxRate: document.getElementById('previewTaxRate'),
            previewTaxAmount: document.getElementById('previewTaxAmount'),
            previewTotal: document.getElementById('previewTotal')
        };
        dynamicElements.addItemBtn.addEventListener('click', () => dynamicElements.invoiceItemsBody.appendChild(createItemRow())); // Cambiado de quoteItemsBody
        dynamicElements.invoiceItemsBody.addEventListener('input', recalculateTotal); // Cambiado de quoteItemsBody
        elements.taxRate.addEventListener('input', recalculateTotal); // Asegura que el cambio de impuesto actualice el total
        dynamicElements.invoiceItemsBody.addEventListener('blur', (e) => { // Cambiado de quoteItemsBody
            // Format price cells on blur
            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);
    };

    const formatStatusText = (status) => (status ? status.replace(/_/g, ' ').toUpperCase() : '');
    const getStatusClass = (status) => {
        const s = status.toLowerCase();
        if (s === 'pagada') return 'bg-green-100 text-green-800'; // Nuevo estado para facturas
        if (s === 'enviada') return 'bg-blue-100 text-blue-800';
        if (s === 'cancelada') return 'bg-red-200 text-red-800'; // Nuevo estado para facturas
        if (s === 'atrasada') return 'bg-orange-200 text-orange-800'; // Nuevo estado para facturas
        if (s === 'generada') return 'bg-gray-300 text-gray-800'; // Nuevo estado
        return 'bg-gray-100 text-gray-800';
    };

    // Eliminada la función translateContactType

    const updateDisplay = () => {
        const monthFilterValue = elements.monthFilter.value; // Usar un nombre de variable más descriptivo
        renderTable(monthFilterValue); // Pasar el valor del filtro directamente a renderTable
        updateDashboardStats(monthFilterValue); // Pasar el valor del filtro directamente a updateDashboardStats
    };

    const renderTable = (monthFilterValue) => { // Recibe el valor del filtro como parámetro
        const filters = {
            term: elements.listSearch.value.toLowerCase(),
            status: elements.listFilterStatus.value
        };

        const filteredData = Object.values(allInvoices).filter(doc => { // Cambiado de allEstimates
            // General filters
            const matchesTerm = doc.cliente.toLowerCase().includes(filters.term);
            const matchesStatus = (filters.status === 'all' || doc.estado === filters.status);

            // Month filter logic (MODIFICADO para mayor robustez)
            let matchesMonth = true;
            if (monthFilterValue !== 'all') {
                const docDate = new Date(doc.fechaSolicitud + 'T00:00:00'); // Parse as UTC date to avoid local timezone shifts
                const filterYear = parseInt(monthFilterValue.substring(0, 4));
                const filterMonth = parseInt(monthFilterValue.substring(5, 7)) - 1; // Month is 0-indexed for Date object

                matchesMonth = (docDate.getFullYear() === filterYear && docDate.getMonth() === filterMonth);
            }

            return matchesTerm && matchesStatus && matchesMonth; // Eliminado matchesContactType
        });

        elements.invoicesTableBody.innerHTML = ''; // Cambiado de estimadosTableBody
        elements.noInvoicesMsg.classList.toggle('hidden', filteredData.length > 0); // Cambiado de noEstimadosMsg
        filteredData.forEach(doc => {
            const row = elements.invoicesTableBody.insertRow(); // Cambiado de estimadosTableBody
            // Eliminado contactTypeClass y la etiqueta de tipo de contacto en la tabla
            row.className = 'border-b hover:bg-gray-50'; // Removed 'responsive-invoices-table' class from row

            // Added data-label attributes for responsive stacking
            row.innerHTML = `
                <td class="py-4 px-6" data-label="FECHA">${doc.fechaSolicitud}</td>
                <td class="py-4 px-6" data-label="CLIENTE">${doc.cliente}</td>
                <td class="py-4 px-6" data-label="SERVICIO">${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">${formatStatusText(doc.estado)}</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">
                        ${doc.estado !== 'pagada' ? `
                            <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 w-full sm:w-auto" onclick="window.app.editInvoice('${doc.id}')" title="Ver/Editar">
                                <i data-lucide="eye" class="w-5 h-5"></i>
                            </button>
                        ` : `
                            <span class="text-gray-400 w-full sm:w-auto" title="Factura Pagada"><i data-lucide="check-circle" class="w-5 h-5"></i> Pagada</span>
                        `}
                        <button class="text-red-600 hover:text-red-800 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>`;
            elements.invoicesTableBody.appendChild(row);
        });
        lucide.createIcons();
        setupStatusChangeListeners(); // Llamar a esta función para adjuntar los listeners
        setupDeleteListeners(); // Llamar a la nueva función para adjuntar listeners de eliminar
        // Se elimina la llamada a setupApprovalButtonsListeners porque ya no se necesitan los botones de aprobación
    };

    const setupStatusChangeListeners = () => {
        document.querySelectorAll('.change-status-btn').forEach(button => {
            button.onclick = null; // Evitar duplicados
            button.addEventListener('click', (event) => { // Usar addEventListener
                const externalId = button.dataset.invoiceId; // Cambiado de estimateId
                const currentStatus = button.dataset.currentStatus;
                showStatusModal(externalId, currentStatus); // Llama a la nueva función del modal
                event.stopPropagation(); // Evitar que el clic se propague a la fila si hay un listener global
            });
        });
    };

    // NUEVA FUNCIÓN: Configurar listeners para el botón de eliminar
    const setupDeleteListeners = () => {
        document.querySelectorAll('.delete-invoice-btn').forEach(button => { // Cambiado de delete-estimate-btn
            button.onclick = null; // Asegurarse de limpiar cualquier onclick previo
            button.addEventListener('click', (event) => {
                const externalId = button.dataset.invoiceId; // Cambiado de estimateId
                // [MODIFICACIÓN CLAVE]: Llamar al modal de confirmación personalizado
                window.app.openConfirmDeleteModal(externalId, 'factura'); // Cambiado a 'factura'
                event.stopPropagation(); // Evitar que el clic se propague
            });
        });
    };

    // La función sendApprovalAction y setupApprovalButtonsListeners se eliminan ya que no se necesita el proceso de aprobación

    const showStatusModal = (externalId, currentStatus) => {
        elements.modalInvoiceId.value = externalId; // Cambiado de modalEstimateId
        // ACTUALIZADO: Nuevos estados para facturas
        const statuses = ['generada', 'enviada', 'cancelada', 'atrasada', 'pagada']; 
        elements.modalStatusSelect.innerHTML = ''; // Limpiar opciones anteriores

        statuses.forEach(status => {
            const option = document.createElement('option');
            option.value = status;
            option.textContent = formatStatusText(status);
            if (status === currentStatus) {
                option.selected = true;
            }
            elements.modalStatusSelect.appendChild(option);
        });

        elements.statusModalOverlay.classList.add('active');
    };

    const hideStatusModal = () => {
        elements.statusModalOverlay.classList.remove('active');
    };


    // NUEVAS FUNCIONES: openModal, closeModal, openConfirmDeleteModal (Copiado de clients.php)
    window.openModal = function(modalId) {
        const modal = document.getElementById(modalId);
        if (!modal) { showToast(`Error: Modal con ID "${modalId}" no encontrado.`, 'error'); return; }
        const modalBox = modal.querySelector('div:first-of-type');
        modal.classList.remove('hidden');
        setTimeout(() => { modalBox.classList.remove('scale-95', 'opacity-0'); }, 50);
        // console.log(`[invoices.php] Modal ${modalId} abierto.`); // Reemplazado
    };

    window.closeModal = function(modalId) {
        const modal = document.getElementById(modalId);
        if (!modal) { showToast(`Error: Modal con ID "${modalId}" no encontrado para cerrar.`, 'error'); return; }
        const modalBox = modal.querySelector('div:first-of-type');
        modalBox.classList.add('scale-95', 'opacity-0');
        setTimeout(() => { modal.classList.add('hidden'); }, 300);
        // console.log(`[invoices.php] Modal ${modalId} cerrado.`); // Reemplazado
    };
    
    window.openConfirmDeleteModal = function(itemId, itemType) {
        if (!elements.confirmDeleteButton || !elements.confirmItemTypeSpan) { showToast("Error: Elementos del modal de confirmación de eliminación no encontrados.", 'error'); return; }
        elements.confirmDeleteButton.dataset.itemId = itemId;  
        elements.confirmDeleteButton.dataset.itemType = itemType;
        elements.confirmItemTypeSpan.textContent = itemType.toUpperCase();
        openModal('confirmDeleteModal');
        // console.log(`[invoices.php] Abriendo modal de confirmación de eliminación para ${itemType} ID: ${itemId}.`); // Reemplazado
    };
    // FIN NUEVAS FUNCIONES

    // MODIFICADA: La lógica de eliminación se ha movido al listener de confirm-delete-button
    // Esta función `deleteInvoice` ahora solo es un placeholder o se usará para iniciar el modal
    const deleteInvoice = async (externalId) => { // Cambiado de deleteQuote
        // Esta función ahora solo inicia el proceso del modal de confirmación
        // La lógica real de eliminación (fetch) se ha movido al evento click de confirm-delete-button
        window.app.openConfirmDeleteModal(externalId, 'factura'); // Cambiado a 'factura'
    };

    const updateInvoiceStatus = async (externalId, newStatus) => { // Cambiado de updateEstimateStatus
        const invoice = allInvoices[externalId]; // Cambiado de allEstimates y estimate
        if (!invoice || !invoice.db_id) {
            showToast('Error: Datos de la factura no encontrados para actualizar el estado.', 'error');
            return;
        }

        try {
            // CAMBIO CLAVE: Ahora llama a invoice-status-update.php
            const response = await fetch('db/invoice-status-update.php', { //
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: invoice.db_id, status: newStatus }) // Solo enviar ID y nuevo estado
            });
            const result = await response.json();

            if (result.success) {
                // allInvoices[externalId].estado = newStatus; // Cambiado de allEstimates (No necesario si se recarga)
                hideStatusModal(); // Cerrar el modal
                showToast(`Estado de la factura actualizado a ${formatStatusText(newStatus)}.`, 'success'); // Added toast
                location.reload(); // Recarga la página para mostrar los cambios
            } else {
                showToast(`Error al actualizar estado: ${result.message}`, 'error');
            }
        } catch (error) {
            console.error('Error de conexión al actualizar el estado:', error);
            showToast('Error de conexión al actualizar el estado de la factura.', 'error');
        }
    };


    const formatToK = (num) => {
        if (num === 0) return '0';
        return Math.abs(num) > 999 ? (Math.sign(num)*((Math.abs(num)/1000).toFixed(1))) + 'k' : Math.sign(num)*Math.abs(num);
    };

    const updateDashboardStats = (monthFilterValue) => { // Recibe el valor del filtro como parámetro
        let clientsCount = 0, monthTotal = 0, pendingCount = 0; // Eliminado prospectsCount
        const dataToProcess = Object.values(allInvoices).filter(doc => { // Cambiado de allEstimates
            // Month filter logic (MODIFICADO para mayor robustez, similar a renderTable)
            let matchesMonth = true;
            if (monthFilterValue !== 'all') {
                const docDate = new Date(doc.fechaSolicitud + 'T00:00:00'); // Parse as UTC date
                const filterYear = parseInt(monthFilterValue.substring(0, 4));
                const filterMonth = parseInt(monthFilterValue.substring(5, 7)) - 1;

                matchesMonth = (docDate.getFullYear() === filterYear && docDate.getMonth() === filterMonth);
            }
            return matchesMonth;
        });
        
        dataToProcess.forEach(invoice => { // Cambiado de estimate
            // if (invoice.contactType === 'prospect') prospectsCount++; // Eliminado
            if (invoice.contactType === 'client') clientsCount++;
            monthTotal += parseFloat(invoice.montoFacturado) || 0; // Cambiado montoEstimado a montoFacturado
            // ACTUALIZADO: Lógica para contar facturas pendientes
            if (invoice.estado === 'enviada' || invoice.estado === 'atrasada') {    
                pendingCount++;
            }
        });
        // elements.statsProspectsCount.textContent = prospectsCount; // Eliminado
        elements.statsClientsCount.textContent = clientsCount;
        elements.statsMonthTotal.textContent = `$${formatToK(monthTotal)}`;
        elements.statsPendingCount.textContent = pendingCount; // Actualizar el conteo de facturas pendientes
    };

    const generatePDF = () => {
        showToast('Generando PDF...', 'info'); // Added toast
        const invoiceElement = document.getElementById('pdf-preview'); // Cambiado de quoteElement
        const addItemBtn = invoiceElement.querySelector('#addItemBtn');
        const originalDisplayAddItem = addItemBtn ? addItemBtn.style.display : '';
        const removeBtns = invoiceElement.querySelectorAll('.remove-item-btn');
        const originalDisplayRemoveBtns = Array.from(removeBtns).map(btn => btn.style.display);
        const invoiceItemsBody = invoiceElement.querySelector('#invoice-items'); // Cambiado de quoteItemsBody
        const originalMarginBottom = invoiceItemsBody ? invoiceItemsBody.style.marginBottom : '';

        // Store original styles of pdf-preview
        const originalWidth = invoiceElement.style.width;
        const originalMargin = invoiceElement.style.margin;
        const originalPadding = invoiceElement.style.padding;
        const originalBoxSizing = invoiceElement.style.boxSizing;

        // Hide UI elements not desired in PDF
        if (addItemBtn) addItemBtn.style.display = 'none';
        removeBtns.forEach(btn => btn.style.display = 'none');
        if (invoiceItemsBody) { // Cambiado de quoteItemsBody
            invoiceItemsBody.style.marginBottom = '20px';
        }

        // Apply temporary styles for consistent rendering (Letter size at 96 DPI)
        invoiceElement.style.width = '816px';  
        invoiceElement.style.margin = '0 auto';
        invoiceElement.style.padding = '32px'; // p-8 is 2rem = 32px
        invoiceElement.style.boxSizing = 'border-box';

        html2canvas(invoiceElement, { // Cambiado de quoteElement
            scale: 2, // Keep scale for higher resolution
            useCORS: true,
            width: 816, // Explicitly set capture width to Letter size in pixels
            // html2canvas will automatically calculate height to maintain aspect ratio
        }).then(canvas => {
            // Revert original styles after capture
            invoiceElement.style.width = originalWidth;
            invoiceElement.style.margin = originalMargin;
            invoiceElement.style.padding = originalPadding;
            invoiceElement.style.boxSizing = originalBoxSizing;

            // Revert UI elements visibility
            if (addItemBtn) addItemBtn.style.display = originalDisplayAddItem;
            removeBtns.forEach((btn, i) => btn.style.display = originalDisplayRemoveBtns[i]);
            if (invoiceItemsBody) { // Cambiado de quoteItemsBody
                invoiceItemsBody.style.marginBottom = originalMarginBottom;
            }

            const imgData = canvas.toDataURL('image/png');
            // 'letter' format is already used, which is 612pt x 792pt (8.5in x 11in)
            const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'letter' });
            const pdfWidth = pdf.internal.pageSize.getWidth(); // 612 pt
            const pdfHeight = pdf.internal.pageSize.getHeight(); // 792 pt
            
            // Calculate image height based on canvas aspect ratio to fit PDF width
            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);
                heightLeft -= pdfHeight;
            }

            pdf.save(`Factura-${dynamicElements.previewInvoiceId.textContent}-${dynamicElements.previewContactName.textContent.replace(/\s+/g, '_')}.pdf`); // Cambiado el nombre del archivo
            showToast('PDF de factura generado.', 'success'); // Added toast
        }).catch(err => {
            // Ensure styles are reverted even on error
            invoiceElement.style.width = originalWidth;
            invoiceElement.style.margin = originalMargin;
            invoiceElement.style.padding = originalPadding;
            invoiceElement.style.boxSizing = originalBoxSizing;
            
            // Revert UI elements visibility even on error
            if (addItemBtn) addItemBtn.style.display = originalDisplayAddItem;
            removeBtns.forEach((btn, i) => btn.style.display = originalDisplayRemoveBtns[i]);
            if (invoiceItemsBody) { // Cambiado de quoteItemsBody
                invoiceItemsBody.style.marginBottom = originalMarginBottom;
            }
            console.error("Error al generar PDF:", err);
            showToast('Error al generar el PDF de la factura.', 'error'); // Added toast
        });
    };

    // MODIFICADO: Updated createItemRow to include delete button and its listener
    const createItemRow = (desc = "Nuevo Ítem", unitPrice = 0.00, qty = 1) => { // Changed default description
        const row = document.createElement('tr');
        row.innerHTML = `
            <td class="p-3 border-b" contenteditable="true">${desc}</td>
            <td class="text-right p-3 item-qty border-b" contenteditable="true">${qty}</td>
            <td class="text-right p-3 item-unit-price border-b" contenteditable="true">$${parseFloat(unitPrice).toFixed(2)}</td>
            <td class="text-right p-3 item-total-price border-b">$${(unitPrice * qty).toFixed(2)}</td>
            <td class="p-3 border-b text-center">
                <button type="button" class="text-red-600 hover:text-red-800 remove-item-btn font-bold text-lg" title="Remove Item">
                    X
                </button>
            </td>
        `;
        // Attach event listener directly when creating the row
        const removeButton = row.querySelector('.remove-item-btn');
        if (removeButton) {
            removeButton.addEventListener('click', () => {
                row.remove(); // Remove the parent row
                recalculateTotal(); // Recalculate totals
                // showToast('Item eliminado de la factura.', 'info'); // Optional: add toast for item removal
            });
        }
        return row;
    };

    // Updated recalculateTotal to handle quantity
    const recalculateTotal = () => {
        if (!dynamicElements.invoiceItemsBody) return; // Cambiado de quoteItemsBody
        let subtotal = 0;
        dynamicElements.invoiceItemsBody.querySelectorAll('tr').forEach(row => { // Cambiado de quoteItemsBody
            const desc = row.cells[0].textContent;
            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;
        dynamicElements.previewSubtotal.textContent = `$${subtotal.toFixed(2)}`;
        dynamicElements.previewTaxRate.textContent = taxRate.toFixed(2);
        dynamicElements.previewTaxAmount.textContent = `$${taxAmount.toFixed(2)}`;
        dynamicElements.previewTotal.textContent = `$${total.toFixed(2)}`;
    };

    const resetGeneratorForm = () => {
        selectedContact = null;
        elements.editingInvoiceId.value = ''; // Cambiado de editingQuoteId
        elements.contactSelectionArea.classList.remove('hidden');
        elements.selectedContactDisplay.classList.add('hidden');
        elements.clientSearch.value = ''; // Limpiar campo de búsqueda de cliente
        // Eliminado elements.prospectSearch.value = '';
        elements.tipoServicio.value = '';
        elements.taxRate.value = 0;
        if(dynamicElements.invoiceItemsBody) dynamicElements.invoiceItemsBody.innerHTML = ''; // Cambiado de quoteItemsBody
        updatePreview();
    };

    // Modified handleContactSelection to store full contact object
    const handleContactSelection = (contact) => {
        selectedContact = contact; // Store the entire contact object including id and type
        elements.contactSelectionArea.classList.add('hidden');
        elements.selectedContactName.textContent = contact.name;
        elements.selectedContactEmail.textContent = contact.email;
        elements.selectedContactDisplay.classList.remove('hidden');
        elements.clientSearch.value = ''; // Limpiar después de seleccionar
        // Eliminado elements.prospectSearch.value = '';
        showToast(`Cliente "${contact.name}" seleccionado.`, 'info'); // Added toast
        updatePreview();
    };

    // INICIO DE LA CORRECCIÓN CLAVE PARA EL NÚMERO DE FACTURA Y LA DIRECCIÓN/EMPRESA
    const updatePreview = () => {
        if (!dynamicElements.previewContactName) return;
        dynamicElements.previewContactName.textContent = selectedContact?.name || "Nombre del Contacto";

        // MODIFICADO: Mostrar SIEMPRE la dirección, sin priorizar la empresa.
        dynamicElements.previewContactAddress.textContent = selectedContact?.address || "Dirección del Contacto";
        
        dynamicElements.previewContactEmail.textContent = selectedContact?.email || "Correo del Contacto";
        dynamicElements.previewContactPhone.textContent = selectedContact?.phone || "Teléfono del Contacto";
        dynamicElements.previewDate.textContent = new Date().toLocaleDateString('es-ES');

        let invoiceNumberDisplay = 'NUEVO'; // Default fallback

        if (elements.editingInvoiceId.value) { // Existing invoice // Cambiado de editingQuoteId
            const externalIdKey = elements.editingInvoiceId.value; // Cambiado de editingQuoteId
            if (allInvoices[externalIdKey] && allInvoices[externalIdKey].db_id !== undefined) { // Cambiado de allEstimates
                const numericId = allInvoices[externalIdKey].db_id; // Cambiado de allEstimates
                if (!isNaN(numericId)) {
                    invoiceNumberDisplay = String(numericId).padStart(3, '0');
                }
            }
        } else { // New invoice
            // Usar el siguiente número disponible para nuevas facturas
            invoiceNumberDisplay = String(nextAvailableInvoiceNumber).padStart(3, '0');
        }
        dynamicElements.previewInvoiceId.textContent = invoiceNumberDisplay; // Cambiado de previewQuoteId
        recalculateTotal();
    };
    // FIN DE LA CORRECCIÓN CLAVE

    // Modified saveInvoice to send client_id and items with quantity
    const saveInvoice = async () => { // Cambiado de saveQuote
        if (!selectedContact) {
            showToast("Por favor, busca y selecciona un cliente para la factura.", 'warning');
            return;
        }
        // Validar que el contacto seleccionado sea un cliente
        if (selectedContact.type !== 'client') {
            showToast("Las facturas solo pueden ser emitidas a clientes. Por favor, selecciona un contacto de tipo 'Cliente'.", 'warning');
            return;
        }

        const itemsData = Array.from(dynamicElements.invoiceItemsBody.querySelectorAll('tr')).map(row => { // Cambiado de quoteItemsBody
            const desc = row.cells[0].textContent;
            const qty = parseInt(row.cells[1].textContent) || 1;
            const unitPrice = parseFloat(row.cells[2].textContent.replace(/[$,]/g, '')) || 0;
            return [desc, unitPrice, qty]; // [description, unit_price, quantity]
        });

        if (itemsData.length === 0 || itemsData.every(item => item[0].trim() === '' && (parseInt(item[2]) || 0) === 0 && parseFloat(item[1]) === 0)) {
            showToast("Por favor, agrega al menos un ítem válido a la factura.", 'warning'); // Cambiado de estimado
            return;
        }

        const invoiceData = { // Cambiado de quoteData
            // Send DB ID if editing, otherwise null for creation
            id: elements.editingInvoiceId.value ? allInvoices[elements.editingInvoiceId.value].db_id : null, // Cambiado de editingQuoteId y allEstimates
            invoice_date: new Date().toISOString().split('T')[0], // Cambiado de estimate_date
            status: 'generada', // Default status for new/saved invoices
            tax_rate: parseFloat(elements.taxRate.value) || 0,
            items: itemsData,
            // Solo enviar client_id, no lead_id
            client_id: selectedContact.id,
            lead_id: null, // Asegurar que sea null
        };

        const apiUrl = invoiceData.id ? 'db/invoice-update.php' : 'db/invoice-create.php'; // Cambiado a invoice-update.php y invoice-create.php
        const method = 'POST'; // Both update and create use POST for JSON payload

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

            if (result.success) {
                showToast(`Factura para ${selectedContact.name} guardada correctamente.`, 'success'); // Cambiado de estimado
                // Si es una nueva factura, actualiza el ID externo en el campo oculto
                if (!invoiceData.id) {    
                    elements.editingInvoiceId.value = result.external_id; // Usa el external_id devuelto // Cambiado de editingQuoteId
                }
                hideGeneratorView(); // Close the panel
                location.reload(); // Recarga la página para mostrar los cambios
            } else {
                showToast(`Error al guardar factura: ${result.message}`, 'error'); // Cambiado de estimado
            }
        } catch (error) {
            console.error('Error al guardar la factura:', error); // Cambiado de estimado
            showToast('Error de conexión al guardar la factura.', 'error'); // Cambiado de estimado
        }
    };

    // La función que ejecuta la eliminación AJAX (ahora llamada desde el modal)
    const executeDeleteInvoice = async (externalId) => { // Cambiado de executeDeleteQuote
        const invoiceToDelete = allInvoices[externalId]; // Cambiado de allEstimates y estimateToDelete
        if (!invoiceToDelete || !invoiceToDelete.db_id) {
            showToast('Error: ID de factura de base de datos no encontrado.', 'error'); // Cambiado de estimado
            return;
        }

        try {
            const response = await fetch('db/invoice-delete.php', { // Cambiado a invoice-delete.php
                method: 'POST', // DELETE via POST as common with PHP
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: invoiceToDelete.db_id }) // Cambiado de estimateToDelete
            });
            const result = await response.json();

            if (result.success) {
                showToast('Factura eliminada con éxito.', 'success'); // Cambiado de estimado
                closeModal('confirmDeleteModal'); // Cierra el modal después de la eliminación
                location.reload(); // Recarga la página para mostrar los cambios
            } else {
                showToast(`Error al eliminar factura: ${result.message}`, 'error'); // Cambiado de estimado
            }
        }
        catch (error) {
            console.error('Error al eliminar la factura:', error); // Cambiado de estimado
            showToast('Error de conexión al eliminar la factura.', 'error'); // Cambiado de estimado
        }
    };

    const setupSearch = (inputEl, suggestionEl, contactType) => {
        inputEl.addEventListener('input', async () => {
            const searchTerm = inputEl.value.toLowerCase();
            suggestionEl.innerHTML = '';
            if (!searchTerm) { suggestionEl.classList.add('hidden'); return; }

            const sourceArray = contactType === 'client' ? allClients : []; // Solo se buscarán clientes
            const matches = sourceArray.filter(c => c.name.toLowerCase().includes(searchTerm) || (c.email && c.email.toLowerCase().includes(searchTerm)));

            if (matches.length > 0) {
                matches.forEach(contact => {
                    const div = document.createElement('div');
                    // Mostrar también la empresa si existe (aunque ahora solo son clientes)
                    const displayInfo = contact.company ?    
                                        `${contact.name} (${contact.company} - ${contact.email})` :
                                        `${contact.name} (${contact.email})`;
                    div.textContent = displayInfo;
                    div.className = 'p-2 hover:bg-gray-100 cursor-pointer text-sm border-b last:border-b-0';
                    div.onclick = () => handleContactSelection(contact);
                    suggestionEl.appendChild(div);
                });
                suggestionEl.classList.remove('hidden');
            } else {
                suggestionEl.classList.add('hidden');
            }
        });
        inputEl.addEventListener('blur', () => {
            setTimeout(() => {
                if (!suggestionEl.matches(':hover')) {
                    suggestionEl.classList.add('hidden');
                }
            }, 200);
        });
    };

    // Function to populate service dropdown
    const populateServiceDropdown = () => {
        elements.tipoServicio.innerHTML = '<option value="">-- Selecciona Un Servicio --</option>';
        const servicesByCategory = {};
        allServices.forEach(service => {
            const category = service.category || 'Sin Categoría';
            if (!servicesByCategory[category]) {
                servicesByCategory[category] = [];
            }
            servicesByCategory[category].push(service);
        });

        for (const category in servicesByCategory) {
            const optgroup = document.createElement('optgroup');
            optgroup.label = category;
            servicesByCategory[category].forEach(service => {
                const option = document.createElement('option');
                option.value = service.id; // Store service ID
                option.textContent = `${service.name} ($${service.price.toFixed(2)})`;
                optgroup.appendChild(option);
            });
            elements.tipoServicio.appendChild(optgroup);
        }
    };

    // Function to handle service selection and add to items
    elements.tipoServicio.addEventListener('change', () => {
        const selectedServiceId = elements.tipoServicio.value;
        if (selectedServiceId) {
            const service = allServices.find(s => s.id == selectedServiceId);
            if (service) {
                // Check if the first row is empty or a default one
                const firstRow = dynamicElements.invoiceItemsBody.querySelector('tr'); // Cambiado de quoteItemsBody
                if (firstRow && (firstRow.cells[0].textContent.trim() === 'Nuevo Ítem' || (firstRow.cells[0].textContent.trim() === '' && parseFloat(firstRow.cells[2].textContent.replace(/[$,]/g, '')) === 0))) {
                    // Update the existing first row
                    firstRow.cells[0].textContent = service.name;
                    firstRow.cells[1].textContent = 1; // Default quantity
                    firstRow.cells[2].textContent = `$${service.price.toFixed(2)}`;
                } else {
                    // Add a new row
                    dynamicElements.invoiceItemsBody.appendChild(createItemRow(service.name, service.price, 1)); // Cambiado de quoteItemsBody
                }
                showToast(`Servicio "${service.name}" agregado.`, 'info'); // Added toast
                recalculateTotal();
            }
        }
    });

    const fetchAndDisplayInvoices = async () => { // Cambiado de fetchAndDisplayEstimates
        try {
            const response = await fetch('db/invoice-read.php'); // Cambiado a invoice-read.php
            const result = await response.json();

            if (result.success) {
                allInvoices = {}; // Reiniciar allInvoices // Cambiado de allEstimates
                let currentMaxDbId = 0; // Track max db_id
                result.data.forEach(invoice => { // Cambiado de estimate
                    allInvoices[invoice.id] = invoice; // Usar external_id como clave // Cambiado de allEstimates
                    if (parseInt(invoice.db_id) > currentMaxDbId) {    
                        currentMaxDbId = parseInt(invoice.db_id);
                    }
                });
                nextAvailableInvoiceNumber = currentMaxDbId + 1; // Set for next new invoice // Cambiado de EstimateNumber
                updateMonthFilterOptions(); // Llama a esta función para actualizar las opciones del filtro de mes.
            } else {
                showToast('Error al cargar facturas: ' + (result.message || 'Error desconocido.'), 'error'); // Cambiado de estimados
                console.error('Error al cargar facturas:', result.message); // Cambiado de estimados
            }
        } catch (error) {
            showToast('Error de conexión al cargar facturas.', 'error'); // Cambiado de estimados
            console.error('Error de conexión al cargar facturas:', error); // Cambiado de estimados
        }
    };

    // Function to update month filter options based on fetched data
    const updateMonthFilterOptions = () => {
        const months = [...new Set(Object.values(allInvoices).map(q => q.fechaSolicitud.substring(0, 7)))].sort().reverse(); // Cambiado de allInvoices
        elements.monthFilter.innerHTML = '<option value="all">TODOS LOS MESES</option>'; // Changed to ALL CAPS
        months.forEach(m => {
            const date = new Date(m + '-02');
            const monthName = date.toLocaleString('es-ES', { month: 'long' });
            const year = date.getFullYear();
            elements.monthFilter.add(new Option(`${monthName.charAt(0).toUpperCase() + monthName.slice(1).toUpperCase()} ${year}`, m)); // Changed to ALL CAPS
        });
        
        // Set the current month as selected by default
        const currentMonthYear = new Date().toISOString().substring(0, 7);
        if (months.includes(currentMonthYear)) {
            elements.monthFilter.value = currentMonthYear;
        } else {
            // Si el mes actual no tiene datos, pero hay otros meses, seleccionar el más reciente con datos
            if (months.length > 0) {
                elements.monthFilter.value = months[0]; // Selecciona el mes más reciente con datos
            } else {
                elements.monthFilter.value = 'all'; // Si no hay datos, por defecto a "Todos los Meses"
            }
        }
    };


    (async function init() {
        // Show PHP errors as toast if they exist
        <?php if (isset($db_error_message) && $db_error_message): ?>
            showToast('<?php echo addslashes($db_error_message); ?>', 'error');
        <?php endif; ?>

        // Fetch clients and services concurrently (eliminado leadsResponse)
        const [clientsResponse, servicesResponse] = await Promise.all([
            fetch('db/clients-read-contact-data.php'), //
            fetch('db/services-read-all.php') //
        ]);

        const [clientsResult, servicesResult] = await Promise.all([
            clientsResponse.json(),
            servicesResponse.json()
        ]);

        if (clientsResult.success) {
            allClients = clientsResult.data;
            setupSearch(elements.clientSearch, elements.clientSuggestions, 'client');
        } else {
            showToast('Error al cargar clientes: ' + (clientsResult.message || 'Error desconocido.'), 'error');
            console.error('Error al cargar clientes:', clientsResult.message);
        }

        // Eliminado el bloque de carga de prospectos

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

        // Initial fetch of invoices
        await fetchAndDisplayInvoices(); // Await this to ensure allInvoices is populated and month filters are updated

        // Setup filters after invoices are loaded and month options are updated
        elements.listFilterStatus.innerHTML = '<option value="all">TODOS LOS ESTADOS</option>';
        // ACTUALIZADO: Estados específicos para facturas
        ['generada', 'enviada', 'cancelada', 'atrasada', 'pagada'].forEach(s => elements.listFilterStatus.add(new Option(formatStatusText(s), s)));
        // Eliminado listFilterContactType
        
        // Se asegura que updateDisplay() se llame solo una vez y después de que todos los datos estén cargados y los filtros iniciales configurados
        updateDisplay();    
        
        // Se modificó el listener para monthFilter para que escuche el evento 'change' explícitamente
        [elements.listSearch, elements.listFilterStatus].forEach(el => el.addEventListener('input', updateDisplay)); // Eliminado listFilterContactType
        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); // Cambiado de saveQuoteBtn
        elements.downloadPdfBtn.addEventListener('click', generatePDF);
        elements.changeContactBtn.addEventListener('click', resetGeneratorForm);
        elements.taxRate.addEventListener('input', recalculateTotal); // Escucha cambios en el campo de impuesto

        // Event listeners for the new status modal
        elements.modalCancelBtn.addEventListener('click', hideStatusModal);
        elements.statusModalOverlay.addEventListener('click', (event) => {
            if (event.target === elements.statusModalOverlay) {
                hideStatusModal();
            }
        });
        elements.modalSaveStatusBtn.addEventListener('click', () => {
            const externalId = elements.modalInvoiceId.value; // Cambiado de modalEstimateId
            const newStatus = elements.modalStatusSelect.value;
            updateInvoiceStatus(externalId, newStatus); // Cambiado de updateEstimateStatus
        });

        // NUEVO: Listener para el botón de Confirmar Eliminación del modal
        if (elements.confirmDeleteButton) {
            elements.confirmDeleteButton.addEventListener('click', async function() {
                const itemId = this.dataset.itemId;
                // Llama a la función que ejecuta la eliminación real
                executeDeleteInvoice(itemId); // Cambiado de executeDeleteQuote
            });
        }


        window.app = {
            editInvoice: showGeneratorView, // Cambiado de editQuote
            // deleteInvoice ahora inicia el modal de confirmación
            deleteInvoice: deleteInvoice, // Cambiado de deleteQuote
            updateInvoiceStatus: updateInvoiceStatus, // Cambiado de updateEstimateStatus
            showStatusModal: showStatusModal,
            // openConfirmDeleteModal ahora es accesible globalmente para ser llamada desde setupDeleteListeners
            openConfirmDeleteModal: window.openConfirmDeleteModal  
        };
        lucide.createIcons();
    })();
});
</script>
</body>
</html>