<?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 del estimado
        $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');

    } 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. 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();
?>
<!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 | Estiados | OrozDesign Multiemdia</title>
    <meta name="description" content="Genera estimados y cotizaciones en LocalCRM: prepara, ajusta y envía propuestas comerciales con claridad y 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 2 px 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; }
        .input-with-icon { position: relative; }
        .input-with-icon input { padding-left: 2.5rem; }
        .input-with-icon .search-icon {
            position: absolute;
            left: 0.75rem;
            top: 50%;
            transform: translateY(-50%);
            color: #A0AEC0;
            pointer-events: none;
        }
        .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);
            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 {
                /* IMPORTANT: Removed display: flex, justify-content, align-items here to prevent conflicts */
                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 ESTIMADOS"
      data-page-subtitle="CREA, EDITA Y ADMINISTRA TUS PRESUPUESTOS"
      data-page-icon="file-text"
      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="user-plus" class="w-12 h-12 text-gray-700"></i>
                        <div>
                            <h3 class="text-lg font-extrabold text-gray-500 mb-1 uppercase">Estimados a Prospectos</h3>
                            <p id="stats-prospects-count" class="text-5xl font-bold text-[var(--color-secondary)] uppercase">0</p>
                            <p class="text-sm text-gray-400 mt-1 uppercase">En el mes seleccionado</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="users" class="w-12 h-12 text-gray-700"></i>
                        <div>
                            <h3 class="text-lg font-extrabold text-gray-500 mb-1 uppercase">Estimados a Clientes</h3>
                            <p id="stats-clients-count" class="text-5xl font-bold text-[var(--color-secondary)] uppercase">0</p>
                            <p class="text-sm text-gray-400 mt-1 uppercase">En el mes seleccionado</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 uppercase">Valor Total Estimado</h3>
                            <p id="stats-month-total" class="text-5xl font-bold text-[var(--color-secondary)] uppercase">$0</p>
                            <p class="text-sm text-gray-400 mt-1 uppercase">En el mes seleccionado</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="file-check" class="w-7 h-7 text-[var(--color-primary)]"></i> TODOS LOS ESTIMADOS</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> Nuevo Estimado</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-contact-type" 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/Prospecto</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="estimadosTableBody"></tbody>
                        </table>
                        <p id="no-estimados-msg" class="text-center text-gray-500 py-8 hidden">AÚN NO HAS GENERADO NINGÚN ESTIMADO</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 Estimado</h1>
                <input type="hidden" id="editing-quote-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 de Contacto</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 class="flex items-center my-4"><hr class="flex-grow border-t border-gray-300"><span class="px-2 text-gray-500 text-sm">O</span><hr class="flex-grow border-t border-gray-300"></div>
                        <div class="space-y-2">
                            <label for="prospectSearch" class="text-sm font-semibold text-gray-700">Buscar Prospecto</label>
                            <div class="relative input-with-icon">
                                <i data-lucide="search" class="search-icon w-5 h-5"></i>
                                <input type="text" id="prospectSearch" placeholder="Nombre Del Prospecto..." autocomplete="off" class="w-full p-2.5 border border-gray-300 rounded-lg">
                                <div id="prospect-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-quote-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="quote-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 DEL ESTIMADO</h3>
        <input type="hidden" id="modal-estimate-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 ESTE <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" id="cancel-delete-btn">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() {
    const urlParams = new URLSearchParams(window.location.search);
    const notificationType = urlParams.get('notification_type');
    const notificationMessage = urlParams.get('notification_message');

    if (notificationType && notificationMessage) {
        if (typeof showToast === 'function') {
            showToast(notificationMessage, notificationType);
        } else {
            console.error("showToast function is not defined.");
        }
    }

    if (window.jspdf) { window.jsPDF = window.jspdf.jsPDF; }

    let allClients = [];
    let allProspects = [];
    let allServices = [];
    let allEstimates = {};
    let nextAvailableEstimateNumber = 1;

    const quoteTemplateHTML = `<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">ESTIMATE</h1><p><strong>Date:</strong> <span id="previewDate"></span></p><p><strong>Estimate No.:</strong> <span id="previewQuoteId"></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">QUOTE 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="quote-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 estimate is valid for 30 days.</p></div>`;

    const elements = {
        generatorView: document.getElementById('generator-view-section'),
        generatorPanel: document.getElementById('generator-panel'),
        generatorOverlay: document.getElementById('generator-overlay'),
        showGeneratorBtn: document.getElementById('show-generator-btn'),
        saveQuoteBtn: document.getElementById('save-quote-btn'),
        downloadPdfBtn: document.getElementById('download-pdf-btn'),
        backToListBtn: document.getElementById('back-to-list-btn'),
        estimadosTableBody: document.getElementById('estimadosTableBody'),
        noEstimadosMsg: document.getElementById('no-estimados-msg'),
        listSearch: document.getElementById('list-search'),
        monthFilter: document.getElementById('month-filter'),
        listFilterContactType: document.getElementById('list-filter-contact-type'),
        listFilterStatus: document.getElementById('list-filter-status'),
        generatorTitle: document.getElementById('generator-title'),
        editingQuoteId: document.getElementById('editing-quote-id'),
        clientSearch: document.getElementById('clientSearch'),
        clientSuggestions: document.getElementById('client-suggestions'),
        prospectSearch: document.getElementById('prospectSearch'),
        prospectSuggestions: document.getElementById('prospect-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'),
        quoteContent: document.getElementById('quote-content'),
        statsProspectsCount: document.getElementById('stats-prospects-count'),
        statsClientsCount: document.getElementById('stats-clients-count'),
        statsMonthTotal: document.getElementById('stats-month-total'),
        statusModalOverlay: document.getElementById('status-modal-overlay'),
        statusModal: document.getElementById('status-modal'),
        modalEstimateId: document.getElementById('modal-estimate-id'),
        modalStatusSelect: document.getElementById('modal-status-select'),
        modalCancelBtn: document.getElementById('modal-cancel-btn'),
        modalSaveStatusBtn: document.getElementById('modal-save-status-btn'),
        confirmDeleteModal: document.getElementById('confirmDeleteModal'),
        confirmDeleteButton: document.getElementById('confirm-delete-button'),
        confirmItemTypeSpan: document.getElementById('confirm-item-type')
    };
    let dynamicElements = {};
    let selectedContact = null;

    const showGeneratorView = (externalId = null) => {
        elements.generatorView.classList.remove('hidden');
        setTimeout(() => { elements.generatorPanel.classList.remove('translate-x-full'); }, 10);
        elements.quoteContent.innerHTML = quoteTemplateHTML;
        lucide.createIcons();
        bindDynamicElements();
        resetGeneratorForm();

        if (externalId && allEstimates[externalId]) {
            const estimate = allEstimates[externalId];
            elements.generatorTitle.textContent = `Editando Estimado #${estimate.id.replace('est-', '')}`;
            elements.editingQuoteId.value = externalId;
            if (estimate.contact) {
                handleContactSelection(estimate.contact);
            }
            elements.taxRate.value = estimate.taxRate || 0;
            dynamicElements.quoteItemsBody.innerHTML = '';
            estimate.items.forEach(([desc, price, quantity = 1]) => dynamicElements.quoteItemsBody.appendChild(createItemRow(desc, price, quantity)));
            if (estimate.items.length > 0) {
                const firstItemDesc = estimate.items[0][0];
                const matchingService = allServices.find(s => s.name === firstItemDesc);
                if (matchingService) {
                    elements.tipoServicio.value = matchingService.id;
                } else {
                    elements.tipoServicio.value = '';
                }
            }
            recalculateTotal();
        } else {
            elements.generatorTitle.textContent = 'Crear Nuevo Estimado';
            elements.editingQuoteId.value = '';
        }
        updatePreview();
    };

    const hideGeneratorView = () => {
        elements.generatorPanel.classList.add('translate-x-full');
        // Removed fetchAndDisplayEstimates() call here. It will be called after successful operation.
        setTimeout(() => { elements.generatorView.classList.add('hidden'); }, 300);
    };

    const bindDynamicElements = () => {
        dynamicElements = {
            quoteItemsBody: document.getElementById('quote-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'),
            previewQuoteId: document.getElementById('previewQuoteId'),
            previewSubtotal: document.getElementById('previewSubtotal'),
            previewTaxRate: document.getElementById('previewTaxRate'),
            previewTaxAmount: document.getElementById('previewTaxAmount'),
            previewTotal: document.getElementById('previewTotal')
        };
        dynamicElements.addItemBtn.addEventListener('click', () => dynamicElements.quoteItemsBody.appendChild(createItemRow()));
        dynamicElements.quoteItemsBody.addEventListener('input', recalculateTotal);
        elements.taxRate.addEventListener('input', recalculateTotal);
        dynamicElements.quoteItemsBody.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);
    };

    const formatStatusText = (status) => (status ? status.replace(/_/g, ' ').toUpperCase() : '');
    const getStatusClass = (status) => {
        const s = status.toLowerCase();
        if (s === 'aprobado') return 'bg-green-100 text-green-800';
        if (s === 'enviado') return 'bg-blue-100 text-blue-800';
        if (s === 'rechazado') return 'bg-red-100 text-red-800';
        if (s === 'en_revision') return 'bg-yellow-100 text-yellow-800';
        if (s === 'generado') return 'bg-gray-300 text-gray-800';
        if (s === 'convertida') return 'bg-green-100 text-green-800';
        return 'bg-gray-100 text-gray-800';
    };

    const translateContactType = (type) => {
        if (type === 'client') return 'CLIENTE';
        if (type === 'prospect') return 'PROSPECTO';
        return type;
    };

    const updateDisplay = () => {
        const monthFilterValue = elements.monthFilter.value;
        renderTable(monthFilterValue);
        updateDashboardStats(monthFilterValue);
    };

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

        const filteredData = Object.values(allEstimates).filter(doc => {
            const matchesTerm = doc.cliente.toLowerCase().includes(filters.term);
            const matchesContactType = (filters.contactType === 'all' || doc.contactType === filters.contactType);
            const matchesStatus = (filters.status === 'all' || doc.estado === filters.status);
            let matchesMonth = true;
            if (monthFilterValue !== 'all') {
                const docDate = new Date(doc.fechaSolicitud + 'T00:00:00');
                const filterYear = parseInt(monthFilterValue.substring(0, 4));
                const filterMonth = parseInt(monthFilterValue.substring(5, 7)) - 1;
                matchesMonth = (docDate.getFullYear() === filterYear && docDate.getMonth() === filterMonth);
            }
            return matchesTerm && matchesContactType && matchesStatus && matchesMonth;
        });

        elements.estimadosTableBody.innerHTML = '';
        elements.noEstimadosMsg.classList.toggle('hidden', filteredData.length > 0);
        filteredData.forEach(doc => {
            const row = elements.estimadosTableBody.insertRow();
            const contactTypeClass = doc.contactType === 'client' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800';
            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/PROSPECTO">
                    <div class="flex flex-col items-end">
                        <span class="font-semibold">${doc.cliente}</span>
                        <span class="text-xs font-bold p-1 rounded ${contactTypeClass}">
                            ${translateContactType(doc.contactType).toUpperCase()}
                        </span>
                    </div>
                </td>
                <td class="py-4 px-6" data-label="SERVICIO">${doc.servicio}</td>
                <td class="py-4 px-6" data-label="MONTO">$${parseFloat(doc.montoEstimado).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 !== 'convertida' ? `
                            <button class="text-gray-500 hover:text-gray-700 change-status-btn w-full sm:w-auto" data-estimate-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-quote-btn w-full sm:w-auto" data-estimate-id="${doc.id}" title="Ver/Editar">
                                <i data-lucide="eye" class="w-5 h-5"></i>
                            </button>
                            <button class="text-green-600 hover:text-green-800 convert-quote-btn w-full sm:w-auto" data-quote-external-id="${doc.id}" title="Convertir a Factura">
                                <i data-lucide="check-circle" class="w-5 h-5"></i>
                            </button>
                        ` : `
                            <span class="text-gray-400 w-full sm:w-auto" title="Cotización Convertida a Factura"><i data-lucide="check-check" class="w-5 h-5"></i> Convertida</span>
                        `}
                        <button class="text-red-600 hover:text-red-800 delete-estimate-btn w-full sm:w-auto" data-estimate-id="${doc.id}" title="Eliminar">
                            <i data-lucide="trash-2" class="w-5 h-5"></i>
                        </button>
                    </div>
                </td>`;
            elements.estimadosTableBody.appendChild(row);
        });
        lucide.createIcons();
        setupStatusChangeListeners();
        setupDeleteListeners();
        setupConvertQuoteListeners();
        setupEditQuoteListeners();
    };

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

    const setupDeleteListeners = () => {
        document.querySelectorAll('.delete-estimate-btn').forEach(button => {
            button.onclick = null;
            button.addEventListener('click', (event) => {
                const externalId = button.dataset.estimateId;
                openConfirmDeleteModal(externalId, 'estimado');
                event.stopPropagation();
            });
        });
    };

    const setupEditQuoteListeners = () => {
        document.querySelectorAll('.edit-quote-btn').forEach(button => {
            button.onclick = null;
            button.addEventListener('click', (event) => {
                const externalId = button.dataset.estimateId;
                showGeneratorView(externalId);
                event.stopPropagation();
            });
        });
    };

    const setupConvertQuoteListeners = () => {
        document.querySelectorAll('.convert-quote-btn').forEach(button => {
            button.onclick = null;
            button.addEventListener('click', async (event) => {
                const quoteExternalId = button.dataset.quoteExternalId;
                const quote = allEstimates[quoteExternalId];
                if (!quote || !quote.db_id) {
                    showToast('Error: Datos de la cotización no encontrados.', 'error');
                    return;
                }
                showToast('Iniciando conversión a factura...', 'info');
                try {
                    const response = await fetch('db/convert-quote-to-invoice.php', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ quote_id: quote.db_id })
                    });
                    const result = await response.json();
                    if (result.success) {
                        showToast(result.message || 'Cotización convertida con éxito.', 'success');
                        allEstimates[quoteExternalId].estado = 'convertida'; // Update local status
                        location.reload(); // Reload to show change in table and potentially other sections
                    } else {
                        showToast(result.message || 'Error al convertir la cotización.', 'error');
                    }
                } catch (error) {
                    console.error('Error de conexión:', error);
                    showToast('Error de conexión al convertir.', 'error');
                }
                event.stopPropagation();
            });
        });
    };

    const showStatusModal = (externalId, currentStatus) => {
        elements.modalEstimateId.value = externalId;
        const statuses = ['generado', 'enviado', 'aprobado', 'rechazado', 'convertida'];
        elements.modalStatusSelect.innerHTML = '';
        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');
    };

    const openModal = function(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'); }, 50);
    };

    const closeModal = function(modalId) {
        const modal = document.getElementById(modalId);
        if (!modal) { return; }
        const modalBox = modal.querySelector('div:first-of-type');
        modalBox.classList.add('scale-95', 'opacity-0');
        setTimeout(() => { modal.classList.add('hidden'); }, 300);
    };

    const openConfirmDeleteModal = function(itemId, itemType) {
        if (!elements.confirmDeleteButton || !elements.confirmItemTypeSpan) { return; }
        elements.confirmDeleteButton.dataset.itemId = itemId;
        elements.confirmDeleteButton.dataset.itemType = itemType;
        elements.confirmItemTypeSpan.textContent = itemType.toUpperCase();
        openModal('confirmDeleteModal');
    };

    const executeDeleteQuote = async (externalId) => {
        const estimateToDelete = allEstimates[externalId];
        if (!estimateToDelete || !estimateToDelete.db_id) {
            showToast('Error: ID de base de datos no encontrado.', 'error');
            return;
        }
        try {
            const response = await fetch('db/quote-delete.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: estimateToDelete.db_id })
            });
            const result = await response.json();
            if (result.success) {
                showToast('Estimado eliminado con éxito.', 'success');
                closeModal('confirmDeleteModal');
                location.reload(); // Reload the page to reflect changes
            } 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 updateEstimateStatus = async (externalId, newStatus) => {
        const estimate = allEstimates[externalId];
        if (!estimate || !estimate.db_id) {
            showToast('Error: Datos del estimado no encontrados.', 'error');
            return;
        }
        try {
            const response = await fetch('db/quote-update.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: estimate.db_id, status: newStatus })
            });
            const result = await response.json();
            if (result.success) {
                // allEstimates[externalId].estado = newStatus; // No needed if reloading
                hideStatusModal();
                showToast('Estado actualizado con éxito.', 'success');
                location.reload(); // Reload the page to reflect changes
            } else {
                showToast(`Error al actualizar estado: ${result.message}`, 'error');
            }
        } catch (error) {
            console.error('Error de conexión:', error);
            showToast('Error de conexión al actualizar estado.', '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) => {
        let prospectsCount = 0, clientsCount = 0, monthTotal = 0;
        const dataToProcess = Object.values(allEstimates).filter(doc => {
            let matchesMonth = true;
            if (monthFilterValue !== 'all') {
                const docDate = new Date(doc.fechaSolicitud + 'T00:00:00');
                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(estimate => {
            if (estimate.contactType === 'prospect') prospectsCount++;
            if (estimate.contactType === 'client') clientsCount++;
            monthTotal += parseFloat(estimate.montoEstimado) || 0;
        });
        elements.statsProspectsCount.textContent = prospectsCount;
        elements.statsClientsCount.textContent = clientsCount;
        elements.statsMonthTotal.textContent = `$${formatToK(monthTotal)}`;
    };

    const generatePDF = () => {
        showToast('Generando PDF...', 'info');
        const quoteElement = document.getElementById('pdf-preview');
        if (!quoteElement) {
            console.error('Element #pdf-preview not found.');
            return;
        }
        const addItemBtn = quoteElement.querySelector('#addItemBtn');
        const originalDisplayAddItem = addItemBtn ? addItemBtn.style.display : '';
        const removeBtns = quoteElement.querySelectorAll('.remove-item-btn');
        const originalDisplayRemoveBtns = Array.from(removeBtns).map(btn => btn.style.display);
        const quoteItemsBody = quoteElement.querySelector('#quote-items'); // Get the tbody
        const originalMarginBottom = quoteItemsBody ? quoteItemsBody.style.marginBottom : ''; // Store its margin-bottom

        if (addItemBtn) addItemBtn.style.display = 'none';
        removeBtns.forEach(btn => btn.style.display = 'none');
        if (quoteItemsBody) {
             quoteItemsBody.style.marginBottom = '20px'; // Add some margin bottom to the tbody for PDF consistency
        }

        // Apply temporary styles for consistent rendering (Letter size at 96 DPI)
        // Adjust these values to match the final PDF output size (8.5in x 11in)
        // 1 inch = 96 pixels (DPI)
        quoteElement.style.width = '816px'; // 8.5 inches * 96 DPI
        quoteElement.style.margin = '0 auto';
        quoteElement.style.padding = '32px'; // p-8 is 2rem = 32px
        quoteElement.style.boxSizing = 'border-box';


        html2canvas(quoteElement, { 
            scale: 2, // Use a higher scale for better resolution in PDF
            useCORS: true,
            width: 816, // Explicitly set capture width to match the letter size
        }).then(canvas => {
            // Revert original styles after capture
            quoteElement.style.width = ''; // Revert to original
            quoteElement.style.margin = ''; // Revert to original
            quoteElement.style.padding = ''; // Revert to original
            quoteElement.style.boxSizing = ''; // Revert to original

            if (addItemBtn) addItemBtn.style.display = originalDisplayAddItem;
            removeBtns.forEach((btn, i) => btn.style.display = originalDisplayRemoveBtns[i]);
            if (quoteItemsBody) {
                quoteItemsBody.style.marginBottom = originalMarginBottom; // Revert margin-bottom
            }

            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);
                heightLeft -= pdfHeight;
            }
            pdf.save(`Estimado-${dynamicElements.previewQuoteId.textContent}-${dynamicElements.previewContactName.textContent.replace(/\s+/g, '_')}.pdf`); // Append contact name
            showToast('PDF generado.', 'success');
        }).catch(err => {
            // Ensure styles are reverted even on error
            quoteElement.style.width = ''; // Revert to original
            quoteElement.style.margin = ''; // Revert to original
            quoteElement.style.padding = ''; // Revert to original
            quoteElement.style.boxSizing = ''; // Revert to original

            if (addItemBtn) addItemBtn.style.display = originalDisplayAddItem;
            removeBtns.forEach((btn, i) => btn.style.display = originalDisplayRemoveBtns[i]);
            if (quoteItemsBody) {
                quoteItemsBody.style.marginBottom = originalMarginBottom; // Revert margin-bottom
            }
            console.error("Error al generar PDF:", err);
            showToast('Error al generar el PDF.', 'error');
        });
    };

    const createItemRow = (desc = "Nuevo Ítem", unitPrice = 0.00, qty = 1) => {
        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>`;
        const removeButton = row.querySelector('.remove-item-btn');
        if (removeButton) {
            removeButton.addEventListener('click', () => {
                row.remove();
                recalculateTotal();
            });
        }
        return row;
    };

    const recalculateTotal = () => {
        if (!dynamicElements.quoteItemsBody) return;
        let subtotal = 0;
        dynamicElements.quoteItemsBody.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;
        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.editingQuoteId.value = '';
        elements.contactSelectionArea.classList.remove('hidden');
        elements.selectedContactDisplay.classList.add('hidden');
        elements.clientSearch.value = '';
        elements.prospectSearch.value = '';
        elements.tipoServicio.value = '';
        elements.taxRate.value = 0;
        if(dynamicElements.quoteItemsBody) dynamicElements.quoteItemsBody.innerHTML = '';
        updatePreview();
    };

    const handleContactSelection = (contact) => {
        selectedContact = contact;
        elements.contactSelectionArea.classList.add('hidden');
        elements.selectedContactName.textContent = contact.name;
        elements.selectedContactEmail.textContent = contact.email;
        // The previous code always used `contact.address`, but `client` and `prospect` data might not always have an exact `address` field.
        // It's safer to check for existence or default to something like empty string if not present.
        // Assuming `address` might come from a `street_address` field in DB data.
        dynamicElements.previewContactAddress.textContent = contact.street_address || contact.address || '';
        elements.selectedContactDisplay.classList.remove('hidden');
        elements.clientSuggestions.classList.add('hidden');
        elements.prospectSuggestions.classList.add('hidden');
        elements.clientSearch.value = '';
        elements.prospectSearch.value = '';
        showToast(`Contacto "${contact.name}" seleccionado.`, 'info');
        updatePreview();
    };

    const updatePreview = () => {
        if (!dynamicElements.previewContactName) return;
        dynamicElements.previewContactName.textContent = selectedContact?.name || "Nombre del Contacto";
        // Ensure address is displayed correctly for both client and prospect, if available
        dynamicElements.previewContactAddress.textContent = selectedContact?.street_address || selectedContact?.address || "Dirección del Contacto"; // Use street_address if present, fallback to general address or default text
        dynamicElements.previewContactEmail.textContent = selectedContact?.email || "Correo del Contacto";
        dynamicElements.previewContactPhone.textContent = selectedContact?.phone || selectedContact?.mobile || "Teléfono del Contacto"; // Use phone or mobile
        dynamicElements.previewDate.textContent = new Date().toLocaleDateString('es-ES');
        let quoteNumberDisplay = 'NUEVO';
        if (elements.editingQuoteId.value) {
            const externalIdKey = elements.editingQuoteId.value;
            if (allEstimates[externalIdKey] && allEstimates[externalIdKey].db_id !== undefined) {
                const numericId = allEstimates[externalIdKey].db_id;
                if (!isNaN(numericId)) {
                    quoteNumberDisplay = String(numericId).padStart(3, '0');
                }
            }
        } else {
            quoteNumberDisplay = String(nextAvailableEstimateNumber).padStart(3, '0');
        }
        dynamicElements.previewQuoteId.textContent = quoteNumberDisplay;
        recalculateTotal();
    };

    const saveQuote = async () => {
        if (!selectedContact) {
            showToast("Por favor, selecciona un contacto.", 'warning');
            return;
        }
        const itemsData = Array.from(dynamicElements.quoteItemsBody.querySelectorAll('tr')).map(row => {
            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];
        });
        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.", 'warning');
            return;
        }
        const quoteData = {
            id: elements.editingQuoteId.value ? allEstimates[elements.editingQuoteId.value].db_id : null,
            estimate_date: new Date().toISOString().split('T')[0],
            status: 'generado',
            tax_rate: parseFloat(elements.taxRate.value) || 0,
            items: itemsData,
            client_id: selectedContact.type === 'client' ? selectedContact.id : null,
            lead_id: selectedContact.type === 'prospect' ? selectedContact.id : null,
        };
        const apiUrl = quoteData.id ? 'db/quote-update.php' : 'db/quote-create.php';
        try {
            const response = await fetch(apiUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(quoteData)
            });
            const result = await response.json();
            if (result.success) {
                showToast(`Estimado guardado correctamente.`, 'success');
                if (!quoteData.id) {
                    elements.editingQuoteId.value = result.external_id;
                }
                hideGeneratorView();
                location.reload(); // Recarga la página para mostrar los cambios
            } 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 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 : allProspects;
            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');
                    const displayInfo = contact.type === 'prospect' && 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);
        });
    };

    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;
                option.textContent = `${service.name} ($${service.price.toFixed(2)})`;
                optgroup.appendChild(option);
            });
            elements.tipoServicio.appendChild(optgroup);
        }
    };

    elements.tipoServicio.addEventListener('change', () => {
        const selectedServiceId = elements.tipoServicio.value;
        if (selectedServiceId) {
            const service = allServices.find(s => s.id == selectedServiceId);
            if (service) {
                const firstRow = dynamicElements.quoteItemsBody.querySelector('tr');
                if (firstRow && (firstRow.cells[0].textContent.trim() === 'Nuevo Ítem' || (firstRow.cells[0].textContent.trim() === '' && parseFloat(firstRow.cells[2].textContent.replace(/[$,]/g, '')) === 0))) {
                    firstRow.cells[0].textContent = service.name;
                    firstRow.cells[1].textContent = 1;
                    firstRow.cells[2].textContent = `$${service.price.toFixed(2)}`;
                } else {
                    dynamicElements.quoteItemsBody.appendChild(createItemRow(service.name, service.price, 1));
                }
                showToast(`Servicio "${service.name}" agregado.`, 'info');
                recalculateTotal();
            }
        }
    });

    const fetchAndDisplayEstimates = async () => {
        try {
            const response = await fetch('db/quote-read.php');
            const result = await response.json();

            if (result.success) {
                allEstimates = {};
                let currentMaxDbId = 0;
                result.data.forEach(estimate => {
                    allEstimates[estimate.id] = estimate;
                    if (parseInt(estimate.db_id) > currentMaxDbId) {
                        currentMaxDbId = parseInt(estimate.db_id);
                    }
                });
                nextAvailableEstimateNumber = currentMaxDbId + 1;
                updateMonthFilterOptions();
                updateDisplay(); // Call updateDisplay here to render after data is fetched
            } else {
                showToast('Error al cargar estimados: ' + (result.message || 'Error desconocido.'), 'error');
                console.error('Error al cargar estimados:', result.message);
            }
        } catch (error) {
            showToast('Error de conexión al cargar estimados.', 'error');
            console.error('Error de conexión al cargar estimados:', error);
        }
    };

    const updateMonthFilterOptions = () => {
        const months = [...new Set(Object.values(allEstimates).map(q => q.fechaSolicitud.substring(0, 7)))].sort().reverse();
        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
        });
        const currentMonthYear = new Date().toISOString().substring(0, 7);
        if (months.includes(currentMonthYear)) {
            elements.monthFilter.value = currentMonthYear;
        } else {
            elements.monthFilter.value = months.length > 0 ? months[0] : 'all';
        }
    };

    (async function init() {
        <?php if (isset($db_error_message) && $db_error_message): ?>
            showToast('<?php echo addslashes($db_error_message); ?>', 'error');
        <?php endif; ?>

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

        const [clientsResult, leadsResult, servicesResult] = await Promise.all([
            clientsResponse.json(),
            leadsResponse.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');
        }
        if (leadsResult.success) {
            allProspects = leadsResult.data;
            setupSearch(elements.prospectSearch, elements.prospectSuggestions, 'prospect');
        } else {
            showToast('Error al cargar prospectos: ' + (leadsResult.message || 'Error desconocido.'), 'error');
        }
        if (servicesResult.success) {
            allServices = servicesResult.data;
            populateServiceDropdown();
        } else {
            showToast('Error al cargar servicios: ' + (servicesResult.message || 'Error desconocido.'), 'error');
        }

        await fetchAndDisplayEstimates(); // This already calls updateDisplay() inside.

        elements.listFilterStatus.innerHTML = '<option value="all">TODOS LOS ESTADOS</option>';
        ['generado', 'enviado', 'aprobado', 'rechazado', 'convertida'].forEach(s => elements.listFilterStatus.add(new Option(formatStatusText(s), s)));
        elements.listFilterContactType.innerHTML = '<option value="all">TODOS LOS CONTACTOS</option>';
        elements.listFilterContactType.add(new Option('CLIENTES', 'client'));
        elements.listFilterContactType.add(new Option('PROSPECTOS', 'prospect'));

        [elements.listSearch, elements.listFilterContactType, 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.saveQuoteBtn.addEventListener('click', saveQuote);
        elements.downloadPdfBtn.addEventListener('click', generatePDF);
        elements.changeContactBtn.addEventListener('click', resetGeneratorForm);
        elements.taxRate.addEventListener('input', recalculateTotal);

        elements.modalCancelBtn.addEventListener('click', hideStatusModal);
        elements.statusModalOverlay.addEventListener('click', (event) => {
            if (event.target === elements.statusModalOverlay) {
                hideStatusModal();
            }
        });
        elements.modalSaveStatusBtn.addEventListener('click', () => {
            const externalId = elements.modalEstimateId.value;
            const newStatus = elements.modalStatusSelect.value;
            updateEstimateStatus(externalId, newStatus);
        });

        // Listener para el botón de cancelar del modal de eliminación
        const cancelDeleteBtn = document.getElementById('cancel-delete-btn');
        if (cancelDeleteBtn) {
            cancelDeleteBtn.addEventListener('click', () => closeModal('confirmDeleteModal'));
        }

        if (elements.confirmDeleteButton) {
            elements.confirmDeleteButton.addEventListener('click', async function() {
                const itemId = this.dataset.itemId;
                executeDeleteQuote(itemId);
            });
        }
        
        lucide.createIcons();
    })();
});
</script>
</body>
</html>