<?php
// includes/finance/finance_quotes.php

// TEMP defaults for testing
$iu_minutes_default = 15;
$iu_rate_default    = 25;

// PRODUCTION 
/*
$iu_minutes_default = (int)getCompanyDetails('iu_minutes_default');
$iu_rate_default    = (float)getCompanyDetails('iu_rate_default');
*/


if ($iu_minutes_default <= 0) {
    $iu_minutes_default = 15;
}
if ($iu_rate_default <= 0) {
    $iu_rate_default = 25;
}

// Build list of active clients for selects
$clients = [];
if (isset($GLOBALS['con']) && $GLOBALS['con'] instanceof mysqli) {
    $sql = "SELECT clientnumber, clientname FROM clientdetails WHERE statuslive = 1 ORDER BY clientname ASC";
    if ($res = $GLOBALS['con']->query($sql)) {
        while ($row = $res->fetch_assoc()) {
            $clients[] = $row;
        }
        $res->close();
    }
}
?>
<div class="container-fluid">
    <div class="row">
        <div class="note note-light mb-3 col-12 col-md-9">
            <strong>Finance Quotations:</strong>
            Use this page to create and track quotations for new enquiries, single inspections, and contract renewals.
            Quotes can be built manually or generated from existing client assets, then emailed as PDFs and converted
            into live clients and invoices when accepted.
        </div>
        <div class="col-12 col-md-3 text-md-end mb-3">
            <button id="btnNewQuote" type="button" class="btn btn-info" data-mdb-tooltip-init data-mdb-placement="top"
                data-mdb-trigger="hover" title="Create a new quotation">
                <i class="fad fa-file-invoice-dollar me-2"></i>New quotation
            </button>
        </div>
    </div>

    <!-- Filters -->
    <div class="row mb-3">
        <div class="col-12 col-md-3 mb-2 mb-md-0">
            <label class="form-label" for="quoteStatusFilter">Status</label>
            <select id="quoteStatusFilter" class="form-select">
                <option value="all">All statuses</option>
                <option value="draft">Draft</option>
                <option value="sent">Sent</option>
                <option value="accepted">Accepted</option>
                <option value="rejected">Rejected</option>
                <option value="expired">Expired</option>
                <option value="converted">Converted</option>
            </select>
        </div>
        <div class="col-12 col-md-3 mb-2 mb-md-0">
            <label class="form-label" for="quoteClientFilter">Client (optional)</label>
            <select id="quoteClientFilter" class="form-select">
                <option value="">All clients</option>
                <?php foreach ($clients as $c): ?>
                <option value="<?php echo (int)$c['clientnumber']; ?>">
                    <?php echo htmlspecialchars($c['clientname']); ?> (<?php echo (int)$c['clientnumber']; ?>)
                </option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="col-12 col-md-3">
            <label class="form-label d-block">&nbsp;</label>
            <button id="btnFilterQuotes" type="button" class="btn btn-secondary me-2" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Apply filters">
                <i class="fad fa-filter me-2"></i>Filter
            </button>
            <button id="btnResetQuotes" type="button" class="btn btn-secondary" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Reset filters">
                <i class="fad fa-undo me-2"></i>Reset
            </button>
        </div>
    </div>

    <!-- Quotes table -->
    <div class="row">
        <div class="col-12">
            <div class="table-responsive">
                <table id="financeQuotesTable" class="table table-striped table-hover align-middle">
                    <thead class="table-dark">
                        <tr>
                            <th>Ref</th>
                            <th>Client / Company</th>
                            <th>Contact</th>
                            <th>Scope</th>
                            <th>Source</th>
                            <th>Status</th>
                            <th>Created</th>
                            <th>Valid until</th>
                            <th class="text-end">Total</th>
                            <th class="text-end">Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <!-- Filled by JS -->
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<script>
function formatGBP(value) {
    const num = Number(value) || 0;
    return '£' + num.toLocaleString('en-GB', {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2
    });
}
window.IU_MINUTES_DEFAULT = <?= (int)$iu_minutes_default ?>;
window.IU_RATE_DEFAULT = <?= (float)$iu_rate_default ?>;

function applyIuDefaults() {
    const minsEl = document.getElementById('iu_minutes_per_unit');
    const rateEl = document.getElementById('iu_rate_per_unit');

    if (minsEl && (!minsEl.value || minsEl.value === '0')) {
        minsEl.value = window.IU_MINUTES_DEFAULT ?? 15;
    }

    if (rateEl && (!rateEl.value || rateEl.value === '0')) {
        rateEl.value = window.IU_RATE_DEFAULT ?? 25;
    }
}

// Refresh quotes list when the financeMailer reports an email has been sent/cancelled
window.addEventListener('enrep:emailSent', (e) => {
    if (e.detail && e.detail.success) {
        showResponse('success', 'Email sent successfully.');
        loadQuotes();
    } else {
        showResponse('warning', 'Email not sent or cancelled.');
    }
});

const quoteModalHTML = `
<form id="quoteForm">
    <input type="hidden" id="quote_id" name="quote_id" value="0">

    <div class="row mb-3">
        <div class="col-12 col-md-4 mb-3 mb-md-0">
            <label class="form-label d-block">Client type</label>
            <div class="form-check form-check-inline">
                <input class="form-check-input" type="radio"
                       name="client_mode" id="clientModeNew" value="new_contact" checked>
                <label class="form-check-label" for="clientModeNew">New contact</label>
            </div>
            <div class="form-check form-check-inline">
                <input class="form-check-input" type="radio"
                       name="client_mode" id="clientModeExisting" value="existing_client">
                <label class="form-check-label" for="clientModeExisting">Existing client</label>
            </div>
        </div>
        <div class="col-12 col-md-4 mb-3 mb-md-0">
            <label class="form-label" for="scope_type">Scope</label>
            <select id="scope_type" name="scope_type" class="form-select">
                <option value="single">Single inspection</option>
                <option value="renewal">Contract renewal</option>
                <option value="new_contract">New contract</option>
                <option value="adhoc">Ad-hoc work</option>
            </select>
        </div>
        <div class="col-12 col-md-4">
            <label class="form-label d-block" for="source_type">Quote basis</label>
            <select id="source_type" name="source_type" class="form-select">
                <option value="manual">Manual entry</option>
                <option value="item_based">Item-based</option>
            </select>
        </div>
    </div>

    <!-- Existing client selection -->
    <div class="row mb-3" id="existingClientRow" style="display:none;">
        <div class="col-12 col-md-6 mb-3 mb-md-0">
            <label class="form-label" for="clientnumber">Client</label>
            <select id="clientnumber" name="clientnumber" class="form-select">
                <option value="">Select client</option>
                <?php foreach ($clients as $c): ?>
                <option value="<?php echo (int)$c['clientnumber']; ?>">
                    <?php echo htmlspecialchars($c['clientname']); ?> (<?php echo (int)$c['clientnumber']; ?>)
                </option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="col-12 col-md-6 d-flex align-items-end">
            <button type="button" class="btn btn-secondary w-100" id="btnBuildFromClient"
                    data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                    title="Build quotation from client's active assets" disabled>
                <i class="fad fa-cogs me-2"></i>Build from assets
            </button>
        </div>
    </div>

    <!-- Contact / company details -->
    <div class="row mb-3">
        <div class="col-12 col-md-3 mb-3 mb-md-0">
            <label class="form-label" for="contact_company">Company</label>
            <input type="text" id="contact_company" name="contact_company" class="form-control"
                   placeholder="Company name">
        </div>
        <div class="col-12 col-md-3">
            <label class="form-label" for="contact_name">Contact name</label>
            <input type="text" id="contact_name" name="contact_name" class="form-control"
                   placeholder="Primary contact">
        </div>

        <div class="col-12 col-md-3 mb-3 mb-md-0">
            <label class="form-label" for="contact_email">Email</label>
            <input type="email" id="contact_email" name="contact_email" class="form-control"
                   placeholder="Email address">
        </div>
        <div class="col-12 col-md-3 mb-3 mb-md-0">
            <label class="form-label" for="contact_phone">Phone</label>
            <input type="text" id="contact_phone" name="contact_phone" class="form-control"
                   placeholder="Phone number">
        </div>
        <div class="col-12 col-md-3">
            <label class="form-label" for="valid_until_display">Valid until</label>
              <div class="w-100 date-picker datepicker" data-date-type="open" data-format="dd-mm-yyyy"
                 data-mdb-toggle-button="false">
                <input
                    type="text"
                    id="valid_until_display"
                    name="valid_until_display"
                    class="form-control"
                    placeholder="dd-mm-yyyy"
                    data-mdb-confirmDateOnSelect
                    data-mdb-toggle="datepicker"
                />
            </div>

            <input type="hidden" id="valid_until" name="valid_until" value="">
        </div>
   

    <!-- Billing address -->
    
        <div class="col-6">
            <label class="form-label" for="billing_address">Billing address</label>
            <textarea id="billing_address" name="billing_address" rows="3" class="form-control"
                      placeholder="Billing address for this quotation"></textarea>
        </div>
    </div>

    <!-- IU summary + items -->
    <div class="row mb-3">
    <div class="col-12 col-md-4 mb-3 mb-md-0" id="iuSummaryCol">
        <div class="card">
            <div class="card-header">
                <strong>Inspection Units summary</strong>
            </div>
            <div class="card-body">
                <div class="row">
                    <div class="col-6">
                        <p class="mb-1"><strong>Total IU:</strong></p>
                        <p class="mb-1"><strong>Hours:</strong></p>
                        <p class="mb-0"><strong>Estimated fee:</strong></p>
                    </div>
                    <div class="col-6 text-end">
                        <p class="mb-1" id="iu_total_units">0</p>
                        <p class="mb-1" id="iu_total_hours">0.00</p>
                        <p class="mb-0" id="iu_total_fee">£0.00</p>
                    </div>
                </div>
                <hr>
                <div class="row g-2">
                    <div class="col-6">
                        <label class="form-label mb-0" for="iu_minutes_per_unit">Minutes per IU</label>
                        <input type="number" class="form-control form-control-sm" id="iu_minutes_per_unit"
                               value="15" step="1" min="1">
                    </div>
                    <div class="col-6">
                        <label class="form-label mb-0" for="iu_rate_per_unit">Fee per IU</label>
                        <input type="number" class="form-control form-control-sm" id="iu_rate_per_unit"
                               value="0" step="0.01" min="0">
                    </div>
                </div>
                <div class="form-text mt-2">
                    IU defaults will later be pulled from client settings.
                </div>
                <div class="mt-2 text-end">
                    <button type="button"
                            id="btnIuReset"
                            class="btn btn-sm btn-warning"
                            data-mdb-tooltip-init
                            data-mdb-placement="top"
                            data-mdb-trigger="hover"
                            title="Reset IU settings to original values">
                        <i class="fad fa-undo me-1"></i>Reset IU
                    </button>
                </div>
            </div>
        </div>
    </div>

        <div class="col-12 col-md-8">
            <div class="card">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <strong>Items / services</strong>
        <div class="d-flex gap-2">
            <button type="button"
                    class="btn btn-sm btn-secondary"
                    id="btnImportCsvQuoteItems"
                    data-mdb-tooltip-init
                    data-mdb-placement="top"
                    data-mdb-trigger="hover"
                    title="Import items from CSV">
                <i class="fad fa-file-csv me-1"></i>Import CSV
            </button>
            <button type="button"
                    class="btn btn-sm btn-secondary"
                    id="btnAddQuoteItem"
                    data-mdb-tooltip-init
                    data-mdb-placement="top"
                    data-mdb-trigger="hover"
                    title="Add new line">
                <i class="fad fa-plus me-1"></i>Add line
            </button>
            <input type="file" id="quoteCsvFile" accept=".csv" class="d-none">
        </div>
    </div>
                <div class="card-body p-0">
                    <div class="table-responsive">
                        <table class="table table-sm align-middle mb-0" id="quoteItemsTable">
                            <thead class="table-light">
                                <tr>
                                    <th style="width:40%;">Description</th>
                                    <th style="width:10%;">Type</th>
                                    <th style="width:10%;">Qty</th>
                                    <th class="text-end" style="width:15%;">Line total</th>
                                    <th class="text-end" style="width:10%;"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <!-- JS rows -->
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- VAT, currency, notes -->
    <div class="row mb-3">

           <input type="hidden" id="vatrate" name="vatrate" value="<?= (float)getCompanyDetails('vat') ?>">

       
        <div class="col-12 ">
            <label class="form-label" for="notes_client">Notes</label>
            <textarea id="notes_client" name="notes_client" rows="3" class="form-control"
                      placeholder="Notes that will appear on the quotation"></textarea>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-12">
            <label class="form-label" for="notes_internal">Internal notes</label>
            <textarea id="notes_internal" name="notes_internal" rows="3" class="form-control"
                      placeholder="Internal notes (not shown to client)"></textarea>
        </div>
    </div>

    <!-- Totals -->
    <div class="row mb-3">
        <div class="col-12 col-md-4 ms-auto">
            <table class="table table-sm mb-0">
                <tr>
                    <th class="text-end">Net total</th>
                    <td class="text-end" id="net_total_display">£0.00</td>
                </tr>
                <tr>
                    <th class="text-end">VAT total</th>
                    <td class="text-end" id="vat_total_display">£0.00</td>
                </tr>
                <tr>
                    <th class="text-end">Gross total</th>
                    <td class="text-end" id="gross_total_display">£0.00</td>
                </tr>
            </table>
        </div>
    </div>

    <input type="hidden" id="created_by" name="created_by"
           value="<?php echo isset($_SESSION['admin_id']) ? (int)$_SESSION['admin_id'] : 0; ?>">
</form>
`;


// Store "base" IU settings for reset
let quoteIUBaseMinutes = 15;
let quoteIUBaseRate = 25;

// Call this once after items have been built or when loading an existing quote
function initIUBaseFromCurrent() {
    const minEl = document.getElementById('iu_minutes_per_unit');
    const rateEl = document.getElementById('iu_rate_per_unit');
    quoteIUBaseMinutes = parseFloat(minEl?.value || '15') || 15;
    quoteIUBaseRate = parseFloat(rateEl?.value || '0') || 0;
}

function bindIUInputs() {
    const minEl = document.getElementById('iu_minutes_per_unit');
    const rateEl = document.getElementById('iu_rate_per_unit');
    const resetBtn = document.getElementById('btnIuReset');

    if (minEl) {
        minEl.addEventListener('input', recalcQuoteTotals);
        minEl.addEventListener('change', recalcQuoteTotals);
    }

    if (rateEl) {
        rateEl.addEventListener('input', recalcQuoteTotals);
        rateEl.addEventListener('change', recalcQuoteTotals);
    }

    if (resetBtn) {
        resetBtn.addEventListener('click', () => {
            const minEl2 = document.getElementById('iu_minutes_per_unit');
            const rateEl2 = document.getElementById('iu_rate_per_unit');

            if (minEl2) minEl2.value = quoteIUBaseMinutes;
            if (rateEl2) rateEl2.value = quoteIUBaseRate.toFixed(2);

            recalcQuoteTotals();
        });
    }
}

// New quote
function openNewQuoteModal() {
    const dest = quoteModalHTML;
    loadModalContent(
        dest,
        "popupBox",
        "modal-xxl",
        1060,
        "true",
        "New quotation",
        "cancelConfirm",
        submitQuoteForm
    );

    setTimeout(function() {
        resetQuoteForm();
        applyIuDefaults();
        initQuoteModalBindings();
    }, 0);
}

// Edit quote
function openEditQuoteModal(payload) {
    const q = payload.quote;
    const items = payload.items || [];

    loadModalContent(
        quoteModalHTML,
        "popupBox",
        "modal-xxl",
        1060,
        "true",
        "Edit quotation " + (q.quote_ref || ''),
        "cancelConfirm",
        submitQuoteForm
    );

    setTimeout(function() {
        resetQuoteForm();
        initQuoteModalBindings();

        document.getElementById('quote_id').value = q.id;

        // Client mode
        const mode = q.client_mode || 'new_contact';
        document.getElementById('clientModeNew').checked = (mode === 'new_contact');
        document.getElementById('clientModeExisting').checked = (mode === 'existing_client');
        handleClientModeChange();

        // Existing client select
        if (mode === 'existing_client') {
            const sel = document.getElementById('clientnumber');
            if (sel) sel.value = q.clientnumber || '';
        }

        // Scope / source
        document.getElementById('scope_type').value = q.scope_type;
        document.getElementById('source_type').value = q.source_type;
        handleSourceTypeChange();

        // Contact + billing
        document.getElementById('contact_company').value = q.contact_company || '';
        document.getElementById('contact_name').value = q.contact_name || '';
        document.getElementById('contact_email').value = q.contact_email || '';
        document.getElementById('contact_phone').value = q.contact_phone || '';
        document.getElementById('billing_address').value = q.billing_address || '';

        // VAT / currency
        document.getElementById('vatrate').value = q.vatrate;
        //document.getElementById('currency').value = q.currency || 'GBP';

        // Notes
        document.getElementById('notes_client').value = q.notes_client || '';
        document.getElementById('notes_internal').value = q.notes_internal || '';

        // Valid until
        if (q.valid_until) {
            const d = new Date(q.valid_until * 1000);
            const dd = String(d.getDate()).padStart(2, '0');
            const mm = String(d.getMonth() + 1).padStart(2, '0');
            const yy = d.getFullYear();
            document.getElementById('valid_until_display').value = dd + '-' + mm + '-' + yy;
            document.getElementById('valid_until').value = q.valid_until;
        }

        // Items
        const tbody = document.querySelector('#quoteItemsTable tbody');
        tbody.innerHTML = '';
        if (items.length) {
            items.forEach(item => addQuoteItemRow(item));
        } else {
            addQuoteItemRow();
        }

        recalcQuoteTotals();
    }, 0);
}

// =========================
// Modal form wiring
// =========================
function initQuoteModalBindings() {
    const modalEl = document.querySelector('#popupBox');
    if (modalEl) initializeDatepickers(modalEl);
    const btnImportCsv = document.getElementById('btnImportCsvQuoteItems');
    const csvInput = document.getElementById('quoteCsvFile');

    if (btnImportCsv && csvInput) {
        btnImportCsv.addEventListener('click', () => {
            csvInput.click();
        });

        csvInput.addEventListener('change', function() {
            if (!this.files || !this.files.length) return;
            const file = this.files[0];
            importQuoteItemsFromCsv(file);
            // reset input so same file can be chosen again if needed
            this.value = '';
        });
    }
    // Client mode
    document.querySelectorAll('input[name="client_mode"]').forEach(r => {
        r.addEventListener('change', handleClientModeChange);
    });

    // Source type
    const st = document.getElementById('source_type');
    if (st) st.addEventListener('change', handleSourceTypeChange);

    // Add line
    const btnAdd = document.getElementById('btnAddQuoteItem');
    if (btnAdd) {
        btnAdd.addEventListener('click', function() {
            addQuoteItemRow();
            recalcQuoteTotals();
        });
    }

    // Build from client (button)
    const btnBuild = document.getElementById('btnBuildFromClient');
    if (btnBuild) {
        btnBuild.addEventListener('click', buildItemsFromClientJS);
    }

    // Client select → autofill & item-based build
    const clientSelect = document.getElementById('clientnumber');
    if (clientSelect) {
        clientSelect.addEventListener('change', handleClientSelectChange);
    }

    // Date -> unix
    const validInput = document.getElementById('valid_until_display');
    if (validInput) {
        validInput.addEventListener('change', function() {
            const parts = this.value.split('-'); // dd-mm-yyyy
            const hidden = document.getElementById('valid_until');
            if (parts.length === 3) {
                const d = new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0],
                        10),
                    12, 0, 0);
                hidden.value = Math.floor(d.getTime() / 1000);
            } else if (hidden) {
                hidden.value = '';
            }
        });
    }

    // First row & initial mode
    const tbody = document.querySelector('#quoteItemsTable tbody');
    if (tbody && !tbody.querySelector('tr')) {
        addQuoteItemRow();
    }

    handleClientModeChange();
    handleSourceTypeChange();
    recalcQuoteTotals();
    initIUBaseFromCurrent();
    bindIUInputs();
}

function importQuoteItemsFromCsv(file) {
    if (!file) return;

    const source = document.getElementById('source_type')?.value || 'manual';
    if (source !== 'item_based') {
        showResponse('warning', 'CSV import is intended for item-based quotations.');
        return;
    }

    const formData = new FormData();
    formData.append('FUNCTION', 'importItemsFromCsv');
    formData.append('tenant', TENANT_URL);
    formData.append('csv_file', file);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_import.php', {
            method: 'POST',
            body: formData
        })
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to import items from CSV.');
                return;
            }

            const items = Array.isArray(data.items) ? data.items : [];
            const unmatched = Array.isArray(data.unmatched) ? data.unmatched : [];

            if (!items.length && !unmatched.length) {
                showResponse('warning', data.message || 'No usable items found in CSV.');
                return;
            }

            const tbody = document.querySelector('#quoteItemsTable tbody');
            if (!tbody) return;

            tbody.innerHTML = '';

            // Matched first (these are IU-based inspection lines)
            items.forEach(item => {
                const row = Object.assign({}, item);
                row.item_type = row.item_type || 'inspection'; // IMPORTANT
                row._origin = 'csv';
                addQuoteItemRow(row);
            });

            // Unmatched after (manual net input)
            unmatched.forEach(item => {
                const row = Object.assign({}, item);
                row.item_type = row.item_type || 'inspection';
                row._origin = 'csv_unmatched';
                addQuoteItemRow(row);

                const tr = tbody.lastElementChild;
                if (tr) {
                    tr.classList.add('table-warning');

                    const descEl = tr.querySelector('.quote-desc');
                    if (descEl && descEl.value && !descEl.value.includes('UNMATCHED')) {
                        descEl.value = descEl.value + ' (UNMATCHED)';
                    }
                }
            });

            recalcQuoteTotals();

            if (unmatched.length) {
                showResponse('warning',
                    `CSV import complete. Matched: ${items.length}, Unmatched: ${unmatched.length}. Unmatched lines need manual completion.`
                );
            } else {
                showResponse('success', `CSV import complete. Matched: ${items.length}.`);
            }
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error importing items from CSV.');
        });
}


// Reset contents when opening
function resetQuoteForm() {
    const form = document.getElementById('quoteForm');
    if (!form) return;
    form.reset();

    document.getElementById('quote_id').value = '0';

    const tbody = document.querySelector('#quoteItemsTable tbody');
    if (tbody) {
        tbody.innerHTML = '';
        addQuoteItemRow();
    }

    document.getElementById('net_total_display').textContent = formatGBP(0);
    document.getElementById('vat_total_display').textContent = formatGBP(0);
    document.getElementById('gross_total_display').textContent = formatGBP(0);

    document.getElementById('iu_total_units').textContent = '0';
    document.getElementById('iu_total_hours').textContent = '0.00';
    document.getElementById('iu_total_fee').textContent = formatGBP(0);
}

function extractUnitsFromDescription(desc) {
    const s = String(desc || '');

    // Matches: "– 0.25 IU per item", "- 1 IU per item", "0.5 IU", etc.
    // Captures the numeric part.
    const m = s.match(/(?:^|[\s–-])(\d+(?:\.\d+)?)\s*IU\b/i);
    if (!m) return 0;

    const v = parseFloat(m[1]);
    return Number.isFinite(v) ? v : 0;
}

// =========================
// Row / totals logic
// =========================
function addQuoteItemRow(data = {}) {
    const tbody = document.querySelector('#quoteItemsTable tbody');
    if (!tbody) return;

    const qty = parseFloat(data.qty ?? data.item_count ?? 1);
    const safeQty = Number.isFinite(qty) ? qty : 1;

    const unitsPerItem =
        parseFloat(data.units_per_item ?? data.units ?? 0) ||
        extractUnitsFromDescription(data.description) ||
        0;

    const isUnmatched = (data._origin === 'csv_unmatched');

    const sourceType = document.getElementById('source_type')?.value || 'manual';
    const isManual = (sourceType === 'manual');

    // IMPORTANT: if older data still sends ui_item, treat it as inspection
    let itemType = (data.item_type || 'inspection');
    if (itemType === 'ui_item') itemType = 'inspection';

    // If manual OR unmatched => show input for line net
    const needsLineInput = (isManual || isUnmatched);

    const lineNetVal = parseFloat(data.net ?? data.line_net ?? 0);
    const safeLineNet = Number.isFinite(lineNetVal) ? lineNetVal : 0;

    const tr = document.createElement('tr');
    tr.dataset.origin = data._origin || '';

    tr.innerHTML = `
        <td>
            <input type="text"
                   class="form-control form-control-sm quote-desc"
                   value="${data.description ?? ''}">
            <input type="hidden" class="quote-units" value="${unitsPerItem}">
        </td>

        <td>
            <select class="form-select form-select-sm quote-type">
                <option value="inspection"${itemType === 'inspection' ? ' selected' : ''}>Inspection</option>
                <option value="service"${itemType === 'service' ? ' selected' : ''}>Service</option>
                <option value="discount"${itemType === 'discount' ? ' selected' : ''}>Discount</option>
                <option value="note"${itemType === 'note' ? ' selected' : ''}>Note</option>
            </select>
        </td>

        <td>
            <input type="number"
                   class="form-control form-control-sm quote-qty"
                   value="${safeQty}"
                   min="0"
                   step="1">
        </td>

        <td class="text-end">
            ${
                needsLineInput
                ? `<input type="number"
                          class="form-control form-control-sm text-end quote-line-net-input"
                          value="${safeLineNet}"
                          min="0"
                          step="0.01"
                          placeholder="0.00">`
                : `<span class="quote-line-total">£0.00</span>`
            }
        </td>

        <td class="text-end">
            <button type="button" class="btn btn-sm btn-danger quote-remove">
                <i class="fad fa-trash-alt"></i>
            </button>
        </td>
    `;

    tbody.appendChild(tr);

    if (isUnmatched) tr.classList.add('table-warning');

    tr.querySelectorAll('input, select').forEach(el => {
        el.addEventListener('input', recalcQuoteTotals);
        el.addEventListener('change', recalcQuoteTotals);
    });

    tr.querySelector('.quote-remove')?.addEventListener('click', () => {
        tr.remove();
        recalcQuoteTotals();
    });

    recalcQuoteTotals();
}


function recalcQuoteTotals() {
    const vatrate = parseFloat(document.getElementById('vatrate')?.value || 0) || 0;
    const ratePerIU = parseFloat(document.getElementById('iu_rate_per_unit')?.value || 0) || 0;
    const minutesPerIU = parseFloat(document.getElementById('iu_minutes_per_unit')?.value || 15) || 15;

    const sourceType = document.getElementById('source_type')?.value || 'manual';
    const isManualMode = (sourceType === 'manual');

    let netTotal = 0;
    let vatTotal = 0;
    let grossTotal = 0;
    let totalIU = 0;

    document.querySelectorAll('#quoteItemsTable tbody tr').forEach(tr => {
        let type = tr.querySelector('.quote-type')?.value || 'inspection';
        const qty = parseFloat(tr.querySelector('.quote-qty')?.value || 0) || 0;
        const unitsPerItem = parseFloat(tr.querySelector('.quote-units')?.value || 0) || 0;

        const isUnmatched = (tr.dataset.origin === 'csv_unmatched');

        // Manual/unmatched rows use manual net input
        const manualNetInput = tr.querySelector('.quote-line-net-input');

        // Legacy safety: if anything still says ui_item, treat as inspection
        if (type === 'ui_item') type = 'inspection';

        let net = 0;

        if ((isManualMode || isUnmatched) && manualNetInput) {
            net = parseFloat(manualNetInput.value || 0) || 0;

        } else if (type === 'inspection') {
            // IU-based inspection line
            const lineIU = qty * unitsPerItem;
            totalIU += lineIU;

            net = lineIU * ratePerIU;

            const out = tr.querySelector('.quote-line-total');
            if (out) out.textContent = formatGBP(net);

        } else if (type === 'discount') {
            // Keep your existing behaviour unless you later add a separate field
            net = -Math.abs(qty * ratePerIU);

            const out = tr.querySelector('.quote-line-total');
            if (out) out.textContent = formatGBP(net);

        } else if (type === 'note') {
            net = 0;
            const out = tr.querySelector('.quote-line-total');
            if (out) out.textContent = formatGBP(net);

        } else {
            // service (no pricing fields shown) => 0 unless you later add another input
            net = 0;
            const out = tr.querySelector('.quote-line-total');
            if (out) out.textContent = formatGBP(net);
        }

        const vat = net * (vatrate / 100);
        const gross = net + vat;

        netTotal += net;
        vatTotal += vat;
        grossTotal += gross;
    });

    document.getElementById('net_total_display').textContent = formatGBP(netTotal);
    document.getElementById('vat_total_display').textContent = formatGBP(vatTotal);
    document.getElementById('gross_total_display').textContent = formatGBP(grossTotal);

    const totalMinutes = totalIU * minutesPerIU;
    const totalHours = totalMinutes / 60;

    document.getElementById('iu_total_units').textContent = totalIU.toFixed(2);
    document.getElementById('iu_total_hours').textContent = totalHours.toFixed(2);
    document.getElementById('iu_total_fee').textContent = formatGBP(totalIU * ratePerIU);
}

// =========================
// Client + assets
// =========================
function handleClientModeChange() {
    const mode = document.querySelector('input[name="client_mode"]:checked')?.value || 'new_contact';
    const row = document.getElementById('existingClientRow');
    if (!row) return;

    if (mode === 'existing_client') {
        row.style.display = '';
    } else {
        row.style.display = 'none';
        const sel = document.getElementById('clientnumber');
        if (sel) sel.value = '';
    }
}

function handleSourceTypeChange() {
    const source = document.getElementById('source_type')?.value || 'manual';

    // Build-from-client button
    const btnBuild = document.getElementById('btnBuildFromClient');
    if (btnBuild) {
        btnBuild.style.display = (source === 'item_based') ? '' : 'none';
    }

    // CSV import button
    const btnCsv = document.getElementById('btnImportCsvQuoteItems');
    if (btnCsv) {
        btnCsv.style.display = (source === 'item_based') ? '' : 'none';
    }

    // IU summary column
    const iuCol = document.getElementById('iuSummaryCol');
    if (iuCol) {
        iuCol.style.display = (source === 'item_based') ? '' : 'none';
    }
}


// on client change: autofill + item-based build if relevant
function handleClientSelectChange() {
    const mode = document.querySelector('input[name="client_mode"]:checked')?.value || 'new_contact';
    const clientnumber = document.getElementById('clientnumber').value.trim();

    if (!clientnumber || mode !== 'existing_client') {
        return;
    }

    // 1) Pull client details
    const params = new URLSearchParams();
    params.append('FUNCTION', 'getClientDetails');
    params.append('tenant', TENANT_URL);
    params.append('clientnumber', clientnumber);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php?' + params.toString())
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success' || !data.data) {
                showResponse('warning', data.message || 'Unable to load client details.');
                return;
            }

            const d = data.data;
            document.getElementById('contact_company').value = d.contact_company || '';
            document.getElementById('contact_name').value = d.contact_name || '';
            document.getElementById('contact_email').value = d.contact_email || '';
            document.getElementById('contact_phone').value = d.contact_phone || '';
            document.getElementById('billing_address').value = d.billing_address || '';
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error loading client details.');
        });

    // 2) If item-based, build right away
    const sourceType = document.getElementById('source_type').value;
    if (sourceType === 'item_based') {
        buildItemsFromClientJS();
    }
}

function buildItemsFromClientJS() {
    const sourceType = document.getElementById('source_type')?.value || 'manual';
    const clientMode = document.querySelector('input[name="client_mode"]:checked')?.value || 'new_contact';
    const clientnumber = document.getElementById('clientnumber')?.value.trim() || '';

    if (sourceType !== 'item_based') {
        showResponse('warning', 'Switch quote basis to item-based first.');
        return;
    }
    if (clientMode !== 'existing_client' || !clientnumber) {
        showResponse('warning', 'Item-based quotations require an existing client selection.');
        return;
    }

    const params = new URLSearchParams();
    params.append('FUNCTION', 'buildItemsFromClient');
    params.append('clientnumber', clientnumber);
    params.append('tenant', TENANT_URL);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php?' + params.toString())
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to build items from client.');
                return;
            }

            const tbody = document.querySelector('#quoteItemsTable tbody');
            if (!tbody) return;

            tbody.innerHTML = '';

            (data.items || []).forEach(item => {
                const row = Object.assign({}, item);
                row.item_type = row.item_type || 'inspection'; // IMPORTANT
                row._origin = 'items';
                addQuoteItemRow(row);
            });

            const rateEl = document.getElementById('iu_rate_per_unit');
            if (data.summary && data.summary.iu_cost && rateEl) {
                rateEl.value = Number(data.summary.iu_cost).toFixed(2);
            }

            recalcQuoteTotals();
            initIUBaseFromCurrent();
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error contacting server for items list.');
        });
}


// =========================
// Save / API calls
// =========================
function submitQuoteForm() {
    const form = document.getElementById('quoteForm');
    if (!form) return;

    const fd = new URLSearchParams();
    fd.append('FUNCTION', 'saveQuote');
    fd.append('tenant', TENANT_URL);

    fd.append('quote_id', document.getElementById('quote_id').value || '0');

    const clientMode = document.querySelector('input[name="client_mode"]:checked')?.value || 'new_contact';
    fd.append('client_mode', clientMode);

    fd.append('clientnumber', document.getElementById('clientnumber')?.value || '');
    fd.append('scope_type', document.getElementById('scope_type')?.value || 'single');
    fd.append('source_type', document.getElementById('source_type')?.value || 'manual');

    fd.append('iu_minutes_per_unit', document.getElementById('iu_minutes_per_unit')?.value || '15');
    fd.append('iu_rate_per_unit', document.getElementById('iu_rate_per_unit')?.value || '0');

    fd.append('contact_company', document.getElementById('contact_company')?.value || '');
    fd.append('contact_name', document.getElementById('contact_name')?.value || '');
    fd.append('contact_email', document.getElementById('contact_email')?.value || '');
    fd.append('contact_phone', document.getElementById('contact_phone')?.value || '');
    fd.append('billing_address', document.getElementById('billing_address')?.value || '');

    fd.append('valid_until', document.getElementById('valid_until')?.value || '');
    fd.append('vatrate', document.getElementById('vatrate')?.value || '0');

    fd.append('notes_client', document.getElementById('notes_client')?.value || '');
    fd.append('notes_internal', document.getElementById('notes_internal')?.value || '');
    fd.append('created_by', document.getElementById('created_by')?.value || '');

    const items = [];
    document.querySelectorAll('#quoteItemsTable tbody tr').forEach(tr => {
        items.push({
            description: tr.querySelector('.quote-desc')?.value.trim() || '',
            item_type: tr.querySelector('.quote-type')?.value || 'inspection',
            qty: parseFloat(tr.querySelector('.quote-qty')?.value || '0'),
            unit_price: parseFloat(tr.querySelector('.quote-unit')?.value || '0')
        });
    });
    fd.append('items', JSON.stringify(items));

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php', {
            method: 'POST',
            body: fd
        })
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to save quotation.');
                return;
            }

            const quoteId = data.quote_id || 0;
            const quoteRef = data.quote_ref || '';
            const clientMode = data.client_mode || 'new_contact';
            const clientnumber = data.clientnumber || '';
            const contactCompany = data.contact_company || '';
            const contactName = data.contact_name || '';
            const contactEmail = data.contact_email || '';

            // Regenerate PDF as part of the save process (fire-and-forget)
            if (quoteId) {
                regenerateQuotePdf(quoteId);
            }

            // Close the quotation modal cleanly
            const popupBoxBody = document.querySelector('#popupBox .modal-body');
            if (popupBoxBody) {
                popupBoxBody.innerHTML = '';
            }
            if (typeof killModal === 'function') {
                killModal('popupBox');
            }

            // Derive a sensible display name: prefer company, then contact, then client select text
            let clientNameLabel = contactCompany || contactName;
            if (!clientNameLabel && clientMode === 'existing_client' && clientnumber) {
                const sel = document.getElementById('clientnumber');
                if (sel && sel.options && sel.selectedIndex >= 0) {
                    clientNameLabel = sel.options[sel.selectedIndex].textContent.trim();
                }
            }

            // Build payload for financeMailer (quote mode)
            const payload = {
                clientNumber: clientnumber || '',
                clientName: clientNameLabel || '',
                primaryEmail: contactEmail || '',
                secondaryEmail: '',
                subject: `Quotation ${quoteRef}${clientNameLabel ? ' - ' + clientNameLabel : ''}`,
                message: 'Please find attached your quotation.',
                filePath: 'quotes',
                fileName: `${quoteRef}_quote.pdf`,
                invoiceNumber: quoteRef, // reuse field; mailer already expects this
                mode: 'quote'
            };

            const encoded = encodeURIComponent(JSON.stringify(payload));

            // Clear any existing email modal body
            const emailBoxBody = document.querySelector('#emailBox .modal-body');
            if (emailBoxBody) {
                emailBoxBody.innerHTML = '';
            }

            const dest = encodeURI(
                ROOT_URL +
                `/includes/master/financeMailer.php?mode=popup&data=${encoded}&tenant=${TENANT_URL}`
            );

            // Open emailer modal for this quote
            loadModalContent(dest, "emailBox", "modal-xl", 1060, "true", "Send Quotation");

            // Notification about save; table refresh will happen on emailSent
            showResponse('success', data.message || 'Quotation saved.');
        })

        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error saving quotation.');
        });
}

function regenerateQuotePdf(quoteId) {
    if (!quoteId) return;

    const post = new URLSearchParams();
    post.append('quote_id', quoteId);
    post.append('tenant', TENANT_URL);

    // Fire-and-forget: no UI, no response handling needed
    fetch(ROOT_URL + '/includes/engines/quote.php', {
        method: 'POST',
        body: post
    }).catch((err) => {
        console.error('Quote PDF generation error', err);
    });
}

// =========================
// List + actions table
// =========================
function loadQuotes() {
    const status = document.getElementById('quoteStatusFilter').value;
    const client = document.getElementById('quoteClientFilter').value.trim();

    const params = new URLSearchParams();
    params.append('FUNCTION', 'listQuotes');
    params.append('tenant', TENANT_URL);
    params.append('status', status);
    if (client) params.append('clientnumber', client);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php?' + params.toString())
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to load quotations.');
                return;
            }

            const tbody = document.querySelector('#financeQuotesTable tbody');
            tbody.innerHTML = '';

            const rows = data.rows || data.data || [];

            if (!rows.length) {
                const tr = document.createElement('tr');
                const td = document.createElement('td');
                td.colSpan = 10;
                td.className = 'text-center text-muted';
                td.textContent = 'No quotations found.';
                tr.appendChild(td);
                tbody.appendChild(tr);
                return;
            }

            const scopeMap = {
                single: 'Single inspection',
                renewal: 'Contract renewal',
                new_contract: 'New contract',
                adhoc: 'Ad-hoc inspection'
            };
            const sourceMap = {
                manual: 'Manual entry',
                item_based: 'Item-based'
            };

            rows.forEach(row => {
                const scopeLabel = scopeMap[row.scope_type] || (row.scope_type ? row.scope_type : '');
                const sourceLabel = sourceMap[row.source_type] || (row.source_type ? row.source_type :
                    '');
                const statusLabel = row.status ? row.status.charAt(0).toUpperCase() + row.status.slice(
                        1) :
                    '';

                let dateCreatedFmt = '';
                if (row.date_created) {
                    const d = new Date(row.date_created * 1000);
                    const dd = String(d.getDate()).padStart(2, '0');
                    const mm = String(d.getMonth() + 1).padStart(2, '0');
                    const yy = d.getFullYear();
                    dateCreatedFmt = `${dd}-${mm}-${yy}`;
                }

                let validUntilFmt = '';
                if (row.valid_until) {
                    const d = new Date(row.valid_until * 1000);
                    const dd = String(d.getDate()).padStart(2, '0');
                    const mm = String(d.getMonth() + 1).padStart(2, '0');
                    const yy = d.getFullYear();
                    validUntilFmt = `${dd}-${mm}-${yy}`;
                }

                // Send / re-send icon state based on status
                let sentTitle;
                let sentIconExtra = '';
                if (row.status === 'sent' || row.status === 'accepted' || row.status === 'converted') {
                    sentTitle = 'Quotation sent (click to re-send email)';
                    sentIconExtra = ' text-success';
                } else {
                    sentTitle = 'Send quotation by email';
                }

                let acceptedTitle = 'Mark as accepted';
                let acceptedIconExtra = '';
                if (row.status === 'accepted') {
                    acceptedTitle = 'Quotation accepted';
                    acceptedIconExtra = ' text-success';
                }

                const tr = document.createElement('tr');
                tr.innerHTML =
                    '<td>' + row.quote_ref + '</td>' +
                    '<td>' + (row.clientname || '') + '</td>' +
                    '<td>' + (row.contact_name || '') + '</td>' +
                    '<td>' + scopeLabel + '</td>' +
                    '<td>' + sourceLabel + '</td>' +
                    '<td>' + statusLabel + '</td>' +
                    '<td>' + dateCreatedFmt + '</td>' +
                    '<td>' + validUntilFmt + '</td>' +
                    '<td class="text-end">' + row.gross_total + '</td>' +
                    '<td class="text-end">' +

                    // --- PREVIEW BUTTON (invoice-style invocation) ---
                    ' <a href="index.php?t=includes/finance/quotes&p=finance_quotes_preview.php' +
                    '&quote_id=' + row.id +
                    '&tenant=' + TENANT_URL + '"' +
                    ' class="btn btn-secondary btn-sm me-1"' +
                    ' data-mdb-toggle="tooltip" data-mdb-placement="top" data-mdb-trigger="hover"' +
                    ' title="Preview quotation">' +
                    ' <i class="fad fa-eye"></i></a>' +

                    // Edit
                    ' <button type="button" class="btn btn-sm btn-secondary me-1 btn-edit-quote"' +
                    '         data-id="' + row.id + '"' +
                    '         data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"' +
                    '         title="Edit quotation"><i class="fad fa-edit"></i></button>' +

                    // Send / re-send
                    ' <button type="button" class="btn btn-sm btn-secondary me-1 btn-status-quote"' +
                    '         data-id="' + row.id + '" data-status="sent"' +
                    '         data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"' +
                    '         title="' + sentTitle + '"><i class="fad fa-paper-plane' + sentIconExtra +
                    '"></i></button>' +

                    // Accepted
                    ' <button type="button" class="btn btn-sm btn-secondary me-1 btn-status-quote"' +
                    '         data-id="' + row.id + '" data-status="accepted"' +
                    '         data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"' +
                    '         title="' + acceptedTitle + '"><i class="fad fa-check-circle' +
                    acceptedIconExtra + '"></i></button>' +

                    // Delete
                    ' <button type="button" class="btn btn-sm btn-secondary btn-delete-quote"' +
                    '         data-id="' + row.id + '" data-ref="' + (row.quote_ref || '') + '"' +
                    '         data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"' +
                    '         title="Delete quotation"><i class="fad fa-trash-alt"></i></button>' +

                    '</td>';

                tbody.appendChild(tr);

            });

            attachQuoteRowHandlers();
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error loading quotations.');
        });
}

function openQuoteEmailerFromList(quoteId) {
    if (!quoteId) return;

    const params = new URLSearchParams();
    params.append('FUNCTION', 'getQuote');
    params.append('tenant', TENANT_URL);
    params.append('quote_id', quoteId);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php?' + params.toString())
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to load quotation.');
                return;
            }

            const q = data.quote;
            if (!q) {
                showResponse('danger', 'Quotation not found.');
                return;
            }

            const quoteRef = q.quote_ref || '';
            const clientnumber = q.clientnumber || '';
            const contactCompany = q.contact_company || '';
            const contactName = q.contact_name || '';
            const contactEmail = q.contact_email || '';

            let clientNameLabel = contactCompany || contactName || '';
            if (!clientNameLabel && clientnumber) {
                clientNameLabel = 'Client ' + clientnumber;
            }

            const payload = {
                clientNumber: clientnumber || '',
                clientName: clientNameLabel || '',
                primaryEmail: contactEmail || '',
                secondaryEmail: '',
                subject: `Quotation ${quoteRef}${clientNameLabel ? ' - ' + clientNameLabel : ''}`,
                message: 'Please find attached your quotation.',
                filePath: 'quotes',
                fileName: `${quoteRef}_quote.pdf`,
                invoiceNumber: quoteRef, // matches what financeMailer already expects
                mode: 'quote'
            };

            const encoded = encodeURIComponent(JSON.stringify(payload));

            const emailBoxBody = document.querySelector('#emailBox .modal-body');
            if (emailBoxBody) {
                emailBoxBody.innerHTML = '';
            }

            const dest = encodeURI(
                ROOT_URL +
                `/includes/master/financeMailer.php?mode=popup&data=${encoded}&tenant=${TENANT_URL}`
            );

            loadModalContent(dest, "emailBox", "modal-xl", 1060, "true", "Send Quotation");
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error preparing quotation email.');
        });
}


function attachQuoteRowHandlers() {
    // Edit
    document.querySelectorAll('.btn-edit-quote').forEach(btn => {
        btn.addEventListener('click', function() {
            const id = this.getAttribute('data-id');

            const params = new URLSearchParams();
            params.append('FUNCTION', 'getQuote');
            params.append('tenant', TENANT_URL);
            params.append('quote_id', id);

            fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php?' + params
                    .toString())
                .then(r => r.json())
                .then(data => {
                    if (data.status !== 'success') {
                        showResponse('danger', data.message || 'Failed to load quotation.');
                        return;
                    }
                    openEditQuoteModal(data);
                })
                .catch(err => {
                    console.error(err);
                    showResponse('danger', 'Error loading quotation.');
                });
        });
    });

    // Status buttons
    document.querySelectorAll('.btn-status-quote').forEach(btn => {
        btn.addEventListener('click', function() {
            const id = this.getAttribute('data-id');
            const status = this.getAttribute('data-status');
            if (!id) return;

            if (status === 'sent') {
                // Both "send" and "re-send" go via financeMailer – mailer handles marking as sent
                openQuoteEmailerFromList(parseInt(id, 10));
            } else {
                // e.g. accepted, rejected, etc. still go via updateStatus
                updateQuoteStatus(id, status);
            }
        });
    });

    // Delete (you can swap this to your modal confirm if/when you want)
    document.querySelectorAll('.btn-delete-quote').forEach(btn => {
        btn.addEventListener('click', function() {
            const id = this.getAttribute('data-id');
            if (!id) return;
            if (!confirm('Are you sure you want to delete this quotation?')) return;
            deleteQuote(id);
        });
    });
}

function updateQuoteStatus(id, status) {
    const fd = new URLSearchParams();
    fd.append('FUNCTION', 'updateStatus');
    fd.append('tenant', TENANT_URL);
    fd.append('quote_id', id);
    fd.append('status', status);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php', {
            method: 'POST',
            body: fd
        })
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to update status.');
                return;
            }
            showResponse('success', data.message || 'Status updated.');
            loadQuotes();
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error updating status.');
        });
}

function openQuoteDeleteModal(id, ref) {
    if (!id) return;

    const safeRef = String(ref || '').replace(/</g, '&lt;').replace(/>/g, '&gt;');

    const dest =
        '<div class="p-3">' +
        '  <p class="mb-2">Are you sure you want to delete quotation <strong>' + safeRef + '</strong>?</p>' +
        '  <p class="mb-0 small text-muted">' +
        'This will remove the quotation from the list. Any related clients or invoices will remain.' +
        '  </p>' +
        '</div>';

    if (typeof loadModalContent === 'function') {
        loadModalContent(
            dest,
            'popupBox',
            'modal-md',
            1060,
            'true',
            'Confirm deletion',
            'cancelConfirm',
            () => deleteQuote(id)
        );
    } else {
        // Fallback if modal loader is unavailable for any reason
        if (confirm('Are you sure you want to delete this quotation?')) {
            deleteQuote(id);
        }
    }
}


function deleteQuote(id) {
    const fd = new URLSearchParams();
    fd.append('FUNCTION', 'deleteQuote');
    fd.append('tenant', TENANT_URL);
    fd.append('quote_id', id);

    fetch(ROOT_URL + '/includes/finance/quotes/finance_quotes_functions.php', {
            method: 'POST',
            body: fd
        })
        .then(r => r.json())
        .then(data => {
            if (data.status !== 'success') {
                showResponse('danger', data.message || 'Failed to delete quotation.');
                return;
            }
            showResponse('success', data.message || 'Quotation deleted.');
            loadQuotes();
        })
        .catch(err => {
            console.error(err);
            showResponse('danger', 'Error deleting quotation.');
        });
}

// =========================
// Page init
// =========================
document.addEventListener('DOMContentLoaded', function() {
    const btnNewQuote = document.getElementById('btnNewQuote');
    if (btnNewQuote) {
        btnNewQuote.addEventListener('click', openNewQuoteModal);
    }

    document.getElementById('btnFilterQuotes').addEventListener('click', loadQuotes);
    document.getElementById('btnResetQuotes').addEventListener('click', function() {
        document.getElementById('quoteStatusFilter').value = 'all';
        document.getElementById('quoteClientFilter').value = '';
        loadQuotes();
    });

    loadQuotes();
});
</script>