<?php

require_once '../../core/config.php';
require_once '../../core/session.php';
require_once '../../core/database.php';
require_once '../../core/format.php';
require_once '../../core/auth.php';
require_once '../../core/permissions.php';
require_once '../../services/billing/BillingDocumentTypeService.php';

require_login();
require_permission('module.billing');

$page_title = 'Facturacion';
$pdo = db();
$environment = defined('FACTO_DEFAULT_ENVIRONMENT') ? FACTO_DEFAULT_ENVIRONMENT : 'sandbox';
$documentService = new BillingDocumentTypeService($pdo);
$documentTypes = $documentService->listIssuedTypes($environment);

$requestedQuoteId = isset($_GET['quote_id']) ? (int)$_GET['quote_id'] : 0;
$fromQuoteView = isset($_GET['from']) && $_GET['from'] === 'quote';
$focusedQuote = null;
$focusNotice = '';

$quoteSelectSql = "
    SELECT
        q.id, q.quote_number, q.status, q.subtotal, q.discount_amount, q.iva, q.total, q.created_at,
        c.customer_name, c.commercial_name, c.legal_name, c.customer_tax_id, c.email_dte, c.email,
        q.facto_document_id, q.invoice_number
    FROM crm_quotes q
    JOIN crm_customers c ON c.id = q.customer_id
    WHERE q.deleted_at IS NULL
";

if ($requestedQuoteId > 0) {
    $stmtFocus = $pdo->prepare($quoteSelectSql . " AND q.id = ? LIMIT 1");
    $stmtFocus->execute(array($requestedQuoteId));
    $focusedQuote = $stmtFocus->fetch(PDO::FETCH_ASSOC) ?: null;
    if (!$focusedQuote) {
        $focusNotice = 'La cotizacion solicitada no existe o esta eliminada.';
    }
}

$listSql = $quoteSelectSql . "
      AND q.status IN ('Aceptada','Facturada','Esperando pago','Pagada')
";
$params = array();
if ($requestedQuoteId > 0) {
    $listSql .= "      AND q.id <> ?
";
    $params[] = $requestedQuoteId;
}
$listSql .= "    ORDER BY q.created_at DESC
    LIMIT 30
";
$stmt = $pdo->prepare($listSql);
$stmt->execute($params);
$quotes = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($focusedQuote) {
    array_unshift($quotes, $focusedQuote);
}

function billing_display_customer($row) {
    if (!empty($row['legal_name'])) return $row['legal_name'];
    if (!empty($row['commercial_name'])) return $row['commercial_name'];
    return $row['customer_name'] ?? '';
}

require_once '../../layouts/header.php';
require_once '../../layouts/sidebar.php';
?>

<main class="app-main" id="billingMain">
    <?php require_once '../../layouts/topbar.php'; ?>

    <section class="content content-no-scroll">
        <div class="page-header page-header-compact fixed-header-section">
            <div class="page-header-content">
                <span class="label">Finanzas · FACTO</span>
                <h1><?php echo $focusedQuote ? 'Generar documento tributario' : 'Facturacion'; ?></h1>
                <p class="text-secondary">
                    <?php if ($focusedQuote): ?>
                        Flujo iniciado desde la cotizacion seleccionada. Valida, previsualiza y emite en sandbox antes de habilitar produccion.
                    <?php else: ?>
                        Paso 5.1: acceso desde cotizacion seleccionada, validacion, preview FACTO y emision controlada en sandbox. Produccion sigue bloqueada.
                    <?php endif; ?>
                </p>
            </div>
        </div>

        <?php if ($focusNotice !== ''): ?>
            <div class="alert alert-warning fixed-header-section" style="margin-bottom:14px;">
                <?php echo safe_text($focusNotice); ?>
            </div>
        <?php endif; ?>

        <?php if ($focusedQuote): ?>
            <div class="card form-card fixed-header-section billing-selected-quote-card">
                <div class="card-body billing-selected-quote-body">
                    <div>
                        <span class="label">Cotizacion seleccionada</span>
                        <h2><?php echo safe_text($focusedQuote['quote_number']); ?></h2>
                        <p class="text-secondary">
                            <?php echo safe_text(billing_display_customer($focusedQuote)); ?> · <?php echo safe_text($focusedQuote['customer_tax_id']); ?> · <?php echo safe_text($focusedQuote['status']); ?> · <?php echo clp($focusedQuote['total']); ?>
                        </p>
                    </div>
                    <div class="billing-selected-quote-actions">
                        <a class="btn btn-secondary" href="/modules/crm/quote_view.php?id=<?php echo (int)$focusedQuote['id']; ?>">Volver a cotizacion</a>
                        <button class="btn btn-primary billing-validate-btn" type="button" data-quote-id="<?php echo (int)$focusedQuote['id']; ?>">
                            Validar documento
                        </button>
                    </div>
                </div>
            </div>
        <?php endif; ?>

        <div class="card form-card fixed-header-section" style="margin-bottom: 14px;">
            <div class="card-body">
                <div class="form-grid form-grid-4">
                    <div class="form-field">
                        <label class="label">Ambiente</label>
                        <select class="input" id="billingEnvironment">
                            <option value="sandbox" <?php echo $environment === 'sandbox' ? 'selected' : ''; ?>>Sandbox</option>
                            <option value="production" <?php echo $environment === 'production' ? 'selected' : ''; ?>>Produccion</option>
                        </select>
                    </div>
                    <div class="form-field">
                        <label class="label">Tipo documento</label>
                        <select class="input" id="billingDocumentKey">
                            <?php foreach ($documentTypes as $type): ?>
                                <?php if ($type['document_family'] === 'receipt') continue; ?>
                                <option value="<?php echo safe_text($type['document_key']); ?>" <?php echo !$type['environment_enabled'] ? 'disabled' : ''; ?>>
                                    <?php echo safe_text($type['document_label']); ?><?php echo !$type['environment_enabled'] ? ' (bloqueado)' : ''; ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="form-field">
                        <label class="label">Fecha emision</label>
                        <input class="input" type="date" id="billingIssueDate" value="<?php echo date('Y-m-d'); ?>">
                    </div>
                    <div class="form-field">
                        <label class="label">Condicion pago</label>
                        <select class="input" id="billingPaymentTerms">
                            <option value="0">Contado</option>
                            <option value="7">7 dias</option>
                            <option value="15">15 dias</option>
                            <option value="30">30 dias</option>
                            <option value="45">45 dias</option>
                        </select>
                    </div>
                </div>
            </div>
        </div>

        <div class="card table-card" style="min-height:0; flex:1; overflow:hidden; display:flex; flex-direction:column;">
            <div class="card-header">
                <h3>Cotizaciones facturables / revisables</h3>
            </div>
            <div class="table-responsive" style="overflow:auto; flex:1;">
                <table class="data-table">
                    <thead>
                        <tr>
                            <th>Folio</th>
                            <th>Cliente</th>
                            <th>Estado</th>
                            <th>Total</th>
                            <th>DTE</th>
                            <th style="width:160px;">Accion</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($quotes as $quote): ?>
                            <tr<?php echo $focusedQuote && (int)$quote['id'] === (int)$focusedQuote['id'] ? ' class="billing-focused-row"' : ''; ?>>
                                <td><strong><?php echo safe_text($quote['quote_number']); ?></strong><?php echo $focusedQuote && (int)$quote['id'] === (int)$focusedQuote['id'] ? '<br><small class="text-secondary">Seleccionada</small>' : ''; ?></td>
                                <td>
                                    <?php echo safe_text(billing_display_customer($quote)); ?><br>
                                    <small class="text-secondary"><?php echo safe_text($quote['customer_tax_id']); ?></small>
                                </td>
                                <td><?php echo safe_text($quote['status']); ?></td>
                                <td><?php echo clp($quote['total']); ?></td>
                                <td><?php echo !empty($quote['facto_document_id']) || !empty($quote['invoice_number']) ? 'Vinculado' : 'Sin emitir'; ?></td>
                                <td>
                                    <button class="btn btn-sm btn-primary billing-validate-btn" type="button" data-quote-id="<?php echo (int)$quote['id']; ?>">
                                        Validar
                                    </button>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                        <?php if (empty($quotes)): ?>
                            <tr><td colspan="6" class="text-secondary">No hay cotizaciones aceptadas o facturables.</td></tr>
                        <?php endif; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </section>
</main>

<style>
    .billing-selected-quote-card { margin-bottom: 14px; border: 1px solid rgba(0, 255, 48, .28); }
    .billing-selected-quote-body { display: flex; justify-content: space-between; align-items: center; gap: 14px; }
    .billing-selected-quote-body h2 { margin: 4px 0; }
    .billing-selected-quote-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
    .billing-focused-row { background: rgba(0, 255, 48, .06); }
    @media (max-width: 760px) {
        .billing-selected-quote-body { flex-direction: column; align-items: stretch; }
        .billing-selected-quote-actions { justify-content: stretch; }
        .billing-selected-quote-actions .btn { width: 100%; }
    }

    #billingValidationModal .billing-modal-box {
        width: 980px;
        max-width: min(96vw, 980px);
        max-height: calc(100dvh - 40px);
    }
    #billingValidationModal .billing-result-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
        margin: 12px 0;
    }
    #billingValidationModal .billing-result-panel {
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-lg);
        padding: 12px;
        background: var(--surface-0);
    }
    #billingValidationModal pre {
        background: var(--surface-0);
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-md);
        padding: 12px;
    }
    #billingValidationModal .billing-action-row {
        display: flex;
        gap: 10px;
        flex-wrap: wrap;
        margin-top: 14px;
        align-items: center;
    }
    #billingValidationModal .billing-pdf-frame {
        width: 100%;
        height: min(68vh, 720px);
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-md);
        background: #fff;
    }
    @media (max-width: 760px) {
        #billingValidationModal .billing-modal-box {
            width: calc(100vw - 18px);
            max-width: calc(100vw - 18px);
            max-height: calc(100dvh - 18px);
        }
        #billingValidationModal .billing-result-grid { grid-template-columns: 1fr; }
    }

.billing-confirm-box{border:1px solid #e5e7eb;border-radius:14px;padding:16px;margin-top:18px;background:#fff;display:grid;gap:12px;}
.billing-confirm-box label{font-weight:600;display:block;}
.billing-check-row{display:flex!important;align-items:center;gap:10px;font-weight:600;}
.billing-paid-fields{grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;}
@media(max-width:768px){.billing-paid-fields{grid-template-columns:1fr;}}
.btn-danger{background:#dc2626!important;color:#fff!important;border-color:#dc2626!important;}

</style>

<div id="billingValidationModal" class="product-modal-backdrop" aria-hidden="true" style="display:none;">
    <div class="product-modal-box billing-modal-box" role="dialog" aria-modal="true" aria-labelledby="billingValidationTitle">
        <div class="product-modal-header">
            <div>
                <span class="label">Validacion tributaria</span>
                <h2 id="billingValidationTitle">Resultado</h2>
            </div>
            <button type="button" class="modal-close" id="billingValidationClose" aria-label="Cerrar">&times;</button>
        </div>
        <div class="product-modal-body">
            <div id="billingValidationContent"></div>
        </div>
        <div class="product-modal-footer">
            <button type="button" class="btn btn-secondary" id="billingValidationCloseFooter">Cerrar</button>
        </div>
    </div>
</div>

<script>
(function(){
    function root(){ return document.getElementById('billingMain'); }

    function esc(value){
        return String(value == null ? '' : value).replace(/[&<>"']/g, function(c){
            return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[c];
        });
    }

    function money(value){
        return new Intl.NumberFormat('es-CL', {
            style: 'currency',
            currency: 'CLP',
            maximumFractionDigits: 0
        }).format(Number(value || 0));
    }

    function getModalParts(){
        return {
            modal: document.getElementById('billingValidationModal'),
            content: document.getElementById('billingValidationContent'),
            title: document.getElementById('billingValidationTitle')
        };
    }

    function openModal(titleText, html){
        const parts = getModalParts();
        if (!parts.modal || !parts.content || !parts.title) {
            alert((titleText || 'Resultado') + "\n\n" + String(html || '').replace(/<[^>]*>/g, ''));
            return;
        }
        parts.title.textContent = titleText || 'Resultado';
        parts.content.innerHTML = html || '';
        parts.modal.style.display = 'flex';
        parts.modal.classList.add('show');
        parts.modal.setAttribute('aria-hidden', 'false');
    }

    function closeModal(){
        const parts = getModalParts();
        if (!parts.modal) return;
        parts.modal.classList.remove('show');
        parts.modal.setAttribute('aria-hidden', 'true');
        setTimeout(function(){
            if (!parts.modal.classList.contains('show')) parts.modal.style.display = 'none';
        }, 180);
    }

    function normalizeErrors(list){
        return Array.isArray(list) ? list : [];
    }

    function renderResult(data){
        const v = data && data.validation ? data.validation : null;
        if (!v) {
            openModal('Error', '<div class="alert alert-error">La respuesta no contiene objeto de validacion.</div>');
            return;
        }

        const errors = normalizeErrors(v.errors);
        const warnings = normalizeErrors(v.warnings);
        const calculation = v.calculation || {};
        const documentType = v.document_type || {};
        const quote = v.quote || {};
        const statusClass = v.ok ? 'alert-success' : 'alert-error';
        const statusTitle = v.ok ? 'Validacion aprobada' : 'Validacion bloqueada';

        let html = '';
        html += '<div class="alert ' + statusClass + '">';
        html += '<strong>' + (v.ok ? 'Preparacion OK' : 'No se puede emitir aun') + '</strong><br>';
        html += esc(documentType.document_label || 'Documento') + ' · ' + esc(quote.quote_number || '') + ' · ' + esc(v.environment || '');
        html += '</div>';

        if (errors.length) {
            html += '<h3>Bloqueos</h3><ul>' + errors.map(function(e){ return '<li>' + esc(e) + '</li>'; }).join('') + '</ul>';
        }
        if (warnings.length) {
            html += '<h3>Advertencias</h3><ul>' + warnings.map(function(e){ return '<li>' + esc(e) + '</li>'; }).join('') + '</ul>';
        }

        html += '<div class="billing-result-grid">';
        html += '<div class="billing-result-panel"><h3>Montos recalculados</h3><table class="data-table"><tbody>';
        html += '<tr><td>Subtotal</td><td>' + money(calculation.subtotal_before_global_discount) + '</td></tr>';
        html += '<tr><td>Descuento global</td><td>' + money(calculation.global_discount_amount) + '</td></tr>';
        html += '<tr><td>Neto afecto</td><td>' + money(calculation.taxable_net_amount) + '</td></tr>';
        html += '<tr><td>Neto exento</td><td>' + money(calculation.exempt_net_amount) + '</td></tr>';
        html += '<tr><td>IVA</td><td>' + money(calculation.taxes_amount) + '</td></tr>';
        html += '<tr><td><strong>Total</strong></td><td><strong>' + money(calculation.total_amount) + '</strong></td></tr>';
        html += '</tbody></table></div>';
        html += '<div class="billing-result-panel"><h3>Control</h3>';
        html += '<p><strong>Idempotency key:</strong><br><code>' + esc(v.idempotency_key || '') + '</code></p>';
        if (v.payment) {
            html += '<p><strong>Vencimiento:</strong><br>' + esc(v.payment.due_date || 'No definido') + '</p>';
        }
        html += '</div></div>';
        html += '<details><summary>Payload preliminar interno</summary><pre style="white-space:pre-wrap;max-height:360px;overflow:auto;">' + esc(JSON.stringify(v.payload_preview || {}, null, 2)) + '</pre></details>';

        if (v.ok) {
            html += '<div class="billing-action-row">';
            html += '<button type="button" class="btn btn-primary billing-preview-btn" data-quote-id="' + esc(quote.id || '') + '">Generar preview FACTO sandbox</button>';
            html += '<span class="text-secondary">No emite documento real. Usa draft_preview en sandbox.</span>';
            html += '</div>';
        }

        openModal(statusTitle, html);
    }


    function renderPreviewResult(data){
        const result = data && data.result ? data.result : null;
        if (!result) {
            openModal('Error', '<div class="alert alert-error">La respuesta no contiene resultado de preview.</div>');
            return;
        }

        const preview = result.preview || {};
        const validation = result.validation || {};
        const quote = validation.quote || {};
        const documentType = validation.document_type || {};
        const summary = result.facto_response_summary || {};
        const ok = !!result.ok;
        let html = '';

        html += '<div class="alert ' + (ok ? 'alert-success' : 'alert-error') + '">';
        html += '<strong>' + (ok ? 'Preview FACTO generado' : 'Preview FACTO con error') + '</strong><br>';
        html += esc(result.message || preview.message || '') + '<br>';
        html += esc(documentType.document_label || 'Documento') + ' · ' + esc(quote.quote_number || '') + ' · sandbox';
        html += '</div>';

        html += '<div class="billing-result-grid">';
        html += '<div class="billing-result-panel"><h3>Resultado FACTO</h3>';
        html += '<p><strong>Log:</strong> #' + esc(preview.log_id || '') + '</p>';
        html += '<p><strong>FACTO document_id:</strong><br>' + esc(preview.facto_document_id || summary.document_id || 'No informado en preview') + '</p>';
        html += '<p><strong>Folio:</strong><br>' + esc(preview.document_number || summary.document_number || 'No informado en preview') + '</p>';
        html += '<p><strong>PDF:</strong> ' + (preview.has_pdf ? 'Disponible' : 'No disponible') + '</p>';
        html += '<p><strong>XML:</strong> ' + (preview.has_xml ? 'Disponible' : 'No disponible') + '</p>';
        html += '</div>';
        html += '<div class="billing-result-panel"><h3>Control</h3>';
        html += '<p><strong>Idempotency key:</strong><br><code>' + esc(validation.idempotency_key || '') + '</code></p>';
        html += '<p><strong>Ambiente:</strong><br>' + esc(preview.environment || 'sandbox') + '</p>';
        html += '</div></div>';

        if (preview.has_pdf && preview.pdf_url) {
            html += '<h3>PDF preliminar</h3>';
            html += '<iframe class="billing-pdf-frame" src="' + esc(preview.pdf_url) + '"></iframe>';
            html += '<div class="billing-action-row"><a class="btn btn-secondary" href="' + esc(preview.pdf_url) + '" target="_blank" rel="noopener">Abrir PDF en nueva pestaña</a></div>';
        } else {
            html += '<div class="alert alert-warning"><strong>Sin PDF preliminar.</strong><br>FACTO respondio, pero no incluyo document_pdf en la respuesta draft_preview. Se guardo el log para revisar respuesta.</div>';
        }

        html += '<details><summary>Resumen respuesta FACTO</summary><pre style="white-space:pre-wrap;max-height:260px;overflow:auto;">' + esc(JSON.stringify(summary, null, 2)) + '</pre></details>';

        if (ok && preview.environment === 'sandbox') {
            html += '<div class="billing-confirm-box">';
            html += '<h3>Confirmar emision sandbox</h3>';
            html += '<p class="text-secondary">Esto emitira el documento en FACTO sandbox, lo vinculara a la cotizacion, actualizara oportunidad/cobranza y creara el registro financiero. Produccion sigue bloqueada.</p>';
            html += '<label class="billing-check-row"><input type="checkbox" id="billingMarkAsPaid" value="1"> Registrar como pagada al emitir</label>';
            html += '<div class="billing-paid-fields" id="billingPaidFields" style="display:none;">';
            html += '<label>Fecha de pago<br><input class="form-control" type="date" id="billingPaymentDate" value="' + esc((new Date()).toISOString().slice(0,10)) + '"></label>';
            html += '<label>Metodo de pago<br><input class="form-control" type="text" id="billingPaymentMethod" placeholder="Transferencia, efectivo, tarjeta..."></label>';
            html += '<label>Nota de pago<br><input class="form-control" type="text" id="billingPaymentNotes" placeholder="Referencia o comentario"></label>';
            html += '</div>';
            html += '<label>Confirmacion<br><input class="form-control" type="text" id="billingIssueConfirmation" placeholder="Escribe EMITIR" autocomplete="off"></label>';
            html += '<div class="billing-action-row">';
            html += '<button type="button" class="btn btn-danger billing-confirm-issue-btn" data-quote-id="' + esc(quote.id || '') + '">Confirmar emision sandbox</button>';
            html += '<span class="text-secondary">Requiere preview previo aprobado e idempotency key sin emision exitosa.</span>';
            html += '</div>';
            html += '</div>';
        }

        openModal(ok ? 'Preview FACTO sandbox' : 'Error preview FACTO', html);
    }

    function renderIssueResult(data){
        const result = data && data.result ? data.result : null;
        if (!result) {
            openModal('Error', '<div class="alert alert-error">La respuesta no contiene resultado de emision.</div>');
            return;
        }

        const issue = result.issue || {};
        const validation = result.validation || {};
        const quote = validation.quote || {};
        const documentType = validation.document_type || {};
        const summary = result.facto_response_summary || {};
        const ok = !!result.ok;
        let html = '';

        html += '<div class="alert ' + (ok ? 'alert-success' : 'alert-error') + '">';
        html += '<strong>' + (ok ? 'Documento emitido en sandbox' : 'Emision con observacion') + '</strong><br>';
        html += esc(result.message || '') + '<br>';
        html += esc(documentType.document_label || 'Documento') + ' · ' + esc(quote.quote_number || '') + ' · sandbox';
        html += '</div>';

        html += '<div class="billing-result-grid">';
        html += '<div class="billing-result-panel"><h3>Resultado FACTO</h3>';
        html += '<p><strong>Log:</strong> #' + esc(issue.log_id || '') + '</p>';
        html += '<p><strong>FACTO document_id:</strong><br>' + esc(issue.facto_document_id || summary.document_id || 'No informado') + '</p>';
        html += '<p><strong>Folio:</strong><br>' + esc(issue.document_number || summary.document_number || 'No informado') + '</p>';
        html += '<p><strong>PDF:</strong> ' + (issue.has_pdf ? 'Disponible' : 'No disponible') + '</p>';
        html += '<p><strong>XML:</strong> ' + (issue.has_xml ? 'Disponible' : 'No disponible') + '</p>';
        html += '</div>';
        html += '<div class="billing-result-panel"><h3>ICYLAB OS</h3>';
        html += '<p><strong>Cotizacion:</strong><br>' + esc(issue.quote_status || 'No actualizada') + '</p>';
        html += '<p><strong>Cobranza:</strong><br>' + esc(issue.payment_status || 'No actualizada') + '</p>';
        html += '<p><strong>Cuenta por cobrar:</strong><br>' + (issue.collection_created ? 'Creada/actualizada' : 'No creada') + '</p>';
        html += '<p><strong>Pago:</strong><br>' + (issue.payment_registered ? 'Registrado' : 'No registrado') + '</p>';
        html += '</div></div>';

        if (issue.has_pdf && issue.pdf_url) {
            html += '<h3>PDF emitido sandbox</h3>';
            html += '<iframe class="billing-pdf-frame" src="' + esc(issue.pdf_url) + '"></iframe>';
            html += '<div class="billing-action-row"><a class="btn btn-secondary" href="' + esc(issue.pdf_url) + '" target="_blank" rel="noopener">Abrir PDF en nueva pestaña</a></div>';
        }

        html += '<details><summary>Resumen respuesta FACTO</summary><pre style="white-space:pre-wrap;max-height:260px;overflow:auto;">' + esc(JSON.stringify(summary, null, 2)) + '</pre></details>';
        openModal(ok ? 'Emision sandbox completada' : 'Emision sandbox pendiente', html);
    }

    async function confirmIssue(button){
        const quoteId = button.getAttribute('data-quote-id');
        const documentKeyEl = document.getElementById('billingDocumentKey');
        const environmentEl = document.getElementById('billingEnvironment');
        const issueDateEl = document.getElementById('billingIssueDate');
        const paymentTermsEl = document.getElementById('billingPaymentTerms');
        const confirmationEl = document.getElementById('billingIssueConfirmation');
        const markAsPaidEl = document.getElementById('billingMarkAsPaid');
        const paymentDateEl = document.getElementById('billingPaymentDate');
        const paymentMethodEl = document.getElementById('billingPaymentMethod');
        const paymentNotesEl = document.getElementById('billingPaymentNotes');

        if (!quoteId || !documentKeyEl || !environmentEl || !issueDateEl || !paymentTermsEl || !confirmationEl) {
            openModal('Error', '<div class="alert alert-error">No se encontraron los campos requeridos para confirmar emision.</div>');
            return;
        }
        if (environmentEl.value !== 'sandbox') {
            openModal('Produccion bloqueada', '<div class="alert alert-error">El Paso 5 solo permite emision en sandbox. Produccion se habilitara despues de cerrar QA.</div>');
            return;
        }
        if ((confirmationEl.value || '').trim().toUpperCase() !== 'EMITIR') {
            openModal('Confirmacion requerida', '<div class="alert alert-error">Debes escribir EMITIR para confirmar la emision sandbox.</div>');
            return;
        }

        const fd = new FormData();
        fd.append('quote_id', quoteId);
        fd.append('document_key', documentKeyEl.value);
        fd.append('environment', environmentEl.value);
        fd.append('issue_date', issueDateEl.value);
        fd.append('payment_terms', paymentTermsEl.value);
        fd.append('confirmation', confirmationEl.value);
        if (markAsPaidEl && markAsPaidEl.checked) {
            fd.append('mark_as_paid', '1');
            fd.append('payment_date', paymentDateEl ? paymentDateEl.value : '');
            fd.append('payment_method', paymentMethodEl ? paymentMethodEl.value : '');
            fd.append('payment_notes', paymentNotesEl ? paymentNotesEl.value : '');
        }

        const oldText = button.textContent;
        button.disabled = true;
        button.textContent = 'Emitiendo...';
        openModal('Emision sandbox', '<p>Confirmando emision en FACTO sandbox. No se usara produccion.</p>');

        try {
            const response = await fetch('/modules/billing/confirm_issue_ajax.php', {
                method: 'POST',
                body: fd,
                credentials: 'same-origin',
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                }
            });
            const raw = await response.text();
            let data = null;
            try { data = JSON.parse(raw); } catch (jsonError) {
                throw new Error('Respuesta no JSON desde confirm_issue_ajax.php. HTTP ' + response.status + '. ' + raw.slice(0, 240));
            }
            if (!response.ok || !data.success) {
                throw new Error((data && data.message) ? data.message : 'Error confirmando emision. HTTP ' + response.status);
            }
            renderIssueResult(data);
        } catch (error) {
            openModal('Error emision FACTO', '<div class="alert alert-error">' + esc(error.message || error) + '</div>');
        } finally {
            button.disabled = false;
            button.textContent = oldText;
        }
    }

    async function previewQuote(button){
        const quoteId = button.getAttribute('data-quote-id');
        const documentKeyEl = document.getElementById('billingDocumentKey');
        const environmentEl = document.getElementById('billingEnvironment');
        const issueDateEl = document.getElementById('billingIssueDate');
        const paymentTermsEl = document.getElementById('billingPaymentTerms');

        if (!quoteId || !documentKeyEl || !environmentEl || !issueDateEl || !paymentTermsEl) {
            openModal('Error', '<div class="alert alert-error">No se encontraron los campos requeridos del formulario de facturacion.</div>');
            return;
        }

        if (environmentEl.value !== 'sandbox') {
            openModal('Produccion bloqueada', '<div class="alert alert-error">El Paso 4 solo permite preview FACTO en sandbox. Produccion se habilitara en el paso de emision real.</div>');
            return;
        }

        const fd = new FormData();
        fd.append('quote_id', quoteId);
        fd.append('document_key', documentKeyEl.value);
        fd.append('environment', environmentEl.value);
        fd.append('issue_date', issueDateEl.value);
        fd.append('payment_terms', paymentTermsEl.value);

        const oldText = button.textContent;
        button.disabled = true;
        button.textContent = 'Generando preview...';
        openModal('Preview FACTO', '<p>Enviando payload a FACTO sandbox con draft_preview. No se emitira documento real.</p>');

        try {
            const response = await fetch('/modules/billing/preview_issue_ajax.php', {
                method: 'POST',
                body: fd,
                credentials: 'same-origin',
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                }
            });

            const raw = await response.text();
            let data = null;
            try {
                data = JSON.parse(raw);
            } catch (jsonError) {
                throw new Error('Respuesta no JSON desde preview_issue_ajax.php. HTTP ' + response.status + '. ' + raw.slice(0, 240));
            }

            if (!response.ok || !data.success) {
                throw new Error((data && data.message) ? data.message : 'Error generando preview. HTTP ' + response.status);
            }

            renderPreviewResult(data);
        } catch (error) {
            openModal('Error preview FACTO', '<div class="alert alert-error">' + esc(error.message || error) + '</div>');
        } finally {
            button.disabled = false;
            button.textContent = oldText;
        }
    }

    async function validateQuote(button){
        const quoteId = button.getAttribute('data-quote-id');
        const documentKeyEl = document.getElementById('billingDocumentKey');
        const environmentEl = document.getElementById('billingEnvironment');
        const issueDateEl = document.getElementById('billingIssueDate');
        const paymentTermsEl = document.getElementById('billingPaymentTerms');

        if (!quoteId || !documentKeyEl || !environmentEl || !issueDateEl || !paymentTermsEl) {
            openModal('Error', '<div class="alert alert-error">No se encontraron los campos requeridos del formulario de facturacion.</div>');
            return;
        }

        const fd = new FormData();
        fd.append('quote_id', quoteId);
        fd.append('document_key', documentKeyEl.value);
        fd.append('environment', environmentEl.value);
        fd.append('issue_date', issueDateEl.value);
        fd.append('payment_terms', paymentTermsEl.value);

        const oldText = button.textContent;
        button.disabled = true;
        button.textContent = 'Validando...';
        openModal('Validando', '<p>Validando cotizacion y datos tributarios...</p>');

        try {
            const response = await fetch('/modules/billing/validate_issue_ajax.php', {
                method: 'POST',
                body: fd,
                credentials: 'same-origin',
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                }
            });

            const raw = await response.text();
            let data = null;
            try {
                data = JSON.parse(raw);
            } catch (jsonError) {
                throw new Error('Respuesta no JSON desde validate_issue_ajax.php. HTTP ' + response.status + '. ' + raw.slice(0, 240));
            }

            if (!response.ok || !data.success) {
                throw new Error((data && data.message) ? data.message : 'Error de validacion. HTTP ' + response.status);
            }
            renderResult(data);
        } catch (error) {
            openModal('Error', '<div class="alert alert-error">' + esc(error.message || error) + '</div>');
        } finally {
            button.disabled = false;
            button.textContent = oldText;
        }
    }

    function bindBillingPage(){
        if (!root()) return;
        const closeTop = document.getElementById('billingValidationClose');
        const closeFooter = document.getElementById('billingValidationCloseFooter');
        if (closeTop && !closeTop.dataset.billingBound) {
            closeTop.dataset.billingBound = '1';
            closeTop.addEventListener('click', closeModal);
        }
        if (closeFooter && !closeFooter.dataset.billingBound) {
            closeFooter.dataset.billingBound = '1';
            closeFooter.addEventListener('click', closeModal);
        }
    }

    if (!window.__ICY_BILLING_VALIDATE_DELEGATED) {
        window.__ICY_BILLING_VALIDATE_DELEGATED = true;
        document.addEventListener('click', function(event){
            const closeBackdrop = event.target && event.target.id === 'billingValidationModal';
            if (closeBackdrop) {
                closeModal();
                return;
            }
            const paidToggle = event.target && event.target.id === 'billingMarkAsPaid';
            if (paidToggle && root()) {
                const paidFields = document.getElementById('billingPaidFields');
                if (paidFields) paidFields.style.display = paidToggle.checked ? 'grid' : 'none';
                return;
            }
            const confirmButton = event.target.closest ? event.target.closest('.billing-confirm-issue-btn') : null;
            if (confirmButton && root()) {
                event.preventDefault();
                confirmIssue(confirmButton);
                return;
            }
            const previewButton = event.target.closest ? event.target.closest('.billing-preview-btn') : null;
            if (previewButton && root()) {
                event.preventDefault();
                previewQuote(previewButton);
                return;
            }
            const button = event.target.closest ? event.target.closest('.billing-validate-btn') : null;
            if (!button || !root()) return;
            event.preventDefault();
            validateQuote(button);
        });
        document.addEventListener('keydown', function(event){
            if (event.key === 'Escape' && root()) closeModal();
        });
        document.addEventListener('icy:spa-after-render', bindBillingPage);
    }

    bindBillingPage();
})();
</script>

<?php require_once '../../layouts/footer.php'; ?>
