<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/includes/layout.php';
require_once dirname(__DIR__) . '/includes/report-data.php';

function crm_quote_post_array(string $key): array
{
    $value = $_POST[$key] ?? [];
    return is_array($value) ? $value : [];
}

function crm_quote_float($value): float
{
    return round(max(0, (float)$value), 2);
}

$db = crm_report_db();
$leadId = max(0, (int)($_POST['lead_id'] ?? $_GET['lead_id'] ?? 0));
$quoteId = max(0, (int)($_POST['quote_id'] ?? $_GET['id'] ?? 0));
$error = '';
$lead = [];
$quote = [];
$products = [];
$statuses = [];
$items = [];
$terms = [];
$savedValues = [];

try {
    if (!$db) {
        throw new RuntimeException('ABOX database connection is unavailable.');
    }
    foreach (['jos_crm_leadentry', 'jos_crm_mcustomers', 'jos_crm_quotations', 'jos_crm_quotation_grid', 'jos_crm_quotation_terms', 'jos_crm_crmproducts'] as $table) {
        if (!crm_report_table($db, $table)) {
            throw new RuntimeException("Required CRM table {$table} is unavailable.");
        }
    }

    if ($quoteId > 0) {
        $quoteRows = crm_report_query($db, "SELECT * FROM jos_crm_quotations WHERE id={$quoteId} LIMIT 1");
        if ($quoteRows === []) {
            throw new RuntimeException('Quotation not found.');
        }
        $quote = $quoteRows[0];
        $leadId = (int)$quote['leadid'];
    }
    if ($leadId <= 0) {
        throw new RuntimeException('Select a lead before generating a quotation.');
    }

    $leadRows = crm_report_query(
        $db,
        "SELECT a.id,a.custid,a.created_by,a.date,a.description,a.leadstatus,
                COALESCE(NULLIF(c.companyname,''),IF(a.custid>0,CONCAT('Customer #',a.custid),'Unassigned customer')) company,
                COALESCE(c.address,'') address,COALESCE(c.gstno,'') gstno,
                COALESCE(NULLIF(c.contactperson1,''),'') contact_person,
                COALESCE(NULLIF(c.contactno1,''),NULLIF(c.contactnumber,''),NULLIF(c.officecontact,''),'') contact_no
         FROM jos_crm_leadentry a LEFT JOIN jos_crm_mcustomers c ON c.id=a.custid
         WHERE a.id={$leadId} LIMIT 1"
    );
    if ($leadRows === []) {
        throw new RuntimeException('Lead not found.');
    }
    $lead = $leadRows[0];
    $products = crm_report_query(
        $db,
        "SELECT id,name,description,hsncode,rate,cgst,igst
         FROM jos_crm_crmproducts ORDER BY ordering,name"
    );
    $statuses = crm_report_query($db, 'SELECT id,name FROM jos_crm_mleadstatus ORDER BY orderid,name');

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (!hash_equals(crm_csrf_token(), (string)($_POST['csrf_token'] ?? ''))) {
            throw new RuntimeException('Your session token expired. Refresh the page and try again.');
        }
        $date = trim((string)($_POST['date'] ?? ''));
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) !== 1) {
            throw new RuntimeException('Enter a valid quotation date.');
        }
        $subject = trim((string)($_POST['description'] ?? ''));
        $description = trim((string)($_POST['descr'] ?? ''));
        if ($subject === '') {
            throw new RuntimeException('Quotation subject is required.');
        }
        $gstType = (int)($_POST['gsttype'] ?? 0) === 1 ? 1 : 0;
        $status = max(0, (int)($_POST['status'] ?? 0));
        $statusIds = array_map(static fn(array $row): int => (int)$row['id'], $statuses);
        if ($status <= 0 || !in_array($status, $statusIds, true)) {
            throw new RuntimeException('Select a valid lead status.');
        }

        $productIds = crm_quote_post_array('product_id');
        $itemDescriptions = crm_quote_post_array('item_description');
        $hsnCodes = crm_quote_post_array('hsncode');
        $rates = crm_quote_post_array('rate');
        $quantities = crm_quote_post_array('qty');
        $discounts = crm_quote_post_array('discount');
        $taxRates = crm_quote_post_array('tax_rate');
        $calculatedItems = [];
        $subtotal = 0.0;
        $gstTotal = 0.0;
        $grandTotal = 0.0;

        foreach ($productIds as $index => $productIdValue) {
            $productId = max(0, (int)$productIdValue);
            $quantity = crm_quote_float($quantities[$index] ?? 0);
            if ($productId <= 0 || $quantity <= 0) {
                continue;
            }
            $rate = crm_quote_float($rates[$index] ?? 0);
            $discount = min(crm_quote_float($discounts[$index] ?? 0), $rate * $quantity);
            $taxRate = min(100, crm_quote_float($taxRates[$index] ?? 0));
            $taxable = round(($rate * $quantity) - $discount, 2);
            $gstAmount = round($taxable * $taxRate / 100, 2);
            $amount = round($taxable + $gstAmount, 2);
            $calculatedItems[] = [
                'product_id' => $productId,
                'description' => trim((string)($itemDescriptions[$index] ?? '')),
                'hsncode' => trim((string)($hsnCodes[$index] ?? '')),
                'rate' => $rate,
                'qty' => $quantity,
                'discount' => $discount,
                'gst' => $taxRate,
                'gstamt' => $gstAmount,
                'amt' => $amount,
            ];
            $subtotal += $taxable;
            $gstTotal += $gstAmount;
            $grandTotal += $amount;
        }
        if ($calculatedItems === []) {
            throw new RuntimeException('Add at least one product with a quantity greater than zero.');
        }

        $termTitles = crm_quote_post_array('term');
        $termDescriptions = crm_quote_post_array('condition');
        $calculatedTerms = [];
        foreach ($termTitles as $index => $termTitle) {
            $termTitle = trim((string)$termTitle);
            $termDescription = trim((string)($termDescriptions[$index] ?? ''));
            if ($termTitle !== '' || $termDescription !== '') {
                $calculatedTerms[] = ['term' => $termTitle, 'description' => $termDescription];
            }
        }

        $createdBy = max(0, (int)($_SESSION['user_id'] ?? $_SESSION['id'] ?? $lead['created_by'] ?? 0));
        $custId = (string)$lead['custid'];
        $smsStatus = '';
        $emailStatus = 0;
        $approved = (int)($quote['approved'] ?? 0);
        $cancelled = (int)($quote['cancelled'] ?? 0);
        $db->begin_transaction();
        try {
            if ($quoteId > 0) {
                $statement = $db->prepare(
                    'UPDATE jos_crm_quotations
                     SET custid=?,created_by=?,date=?,status=?,leadid=?,description=?,subtotal=?,gst=?,total=?,gsttype=?,
                         smsstatus=?,emailstatus=?,descr=?,approved=?,cancelled=? WHERE id=?'
                );
                $statement->bind_param(
                    'sissisdddisisiii',
                    $custId, $createdBy, $date, $status, $leadId, $subject, $subtotal, $gstTotal, $grandTotal,
                    $gstType, $smsStatus, $emailStatus, $description, $approved, $cancelled, $quoteId
                );
                $statement->execute();
                $db->query("DELETE FROM jos_crm_quotation_grid WHERE qutid={$quoteId}");
                $db->query("DELETE FROM jos_crm_quotation_terms WHERE qutid={$quoteId}");
            } else {
                $statement = $db->prepare(
                    'INSERT INTO jos_crm_quotations
                     (custid,created_by,date,status,leadid,description,subtotal,gst,total,gsttype,smsstatus,emailstatus,descr,approved,cancelled)
                     VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'
                );
                $statement->bind_param(
                    'sissisdddisisii',
                    $custId, $createdBy, $date, $status, $leadId, $subject, $subtotal, $gstTotal, $grandTotal,
                    $gstType, $smsStatus, $emailStatus, $description, $approved, $cancelled
                );
                $statement->execute();
                $quoteId = (int)$db->insert_id;
            }

            $itemStatement = $db->prepare(
                'INSERT INTO jos_crm_quotation_grid
                 (qutid,date,propid,hsncode,description,rate,qty,discount,gst,gstamt,amt,status)
                 VALUES (?,?,?,?,?,?,?,?,?,?,?,1)'
            );
            foreach ($calculatedItems as $item) {
                $itemStatement->bind_param(
                    'isissdddddd',
                    $quoteId, $date, $item['product_id'], $item['hsncode'], $item['description'],
                    $item['rate'], $item['qty'], $item['discount'], $item['gst'], $item['gstamt'], $item['amt']
                );
                $itemStatement->execute();
            }
            $termStatement = $db->prepare(
                'INSERT INTO jos_crm_quotation_terms (qutid,date,term,description) VALUES (?,?,?,?)'
            );
            foreach ($calculatedTerms as $term) {
                $termStatement->bind_param('isss', $quoteId, $date, $term['term'], $term['description']);
                $termStatement->execute();
            }
            $db->commit();
            header('Location: ' . crm_url('operations/quotation-view.php?id=' . $quoteId . '&saved=1'));
            exit;
        } catch (Throwable $saveError) {
            $db->rollback();
            throw $saveError;
        }
    }

    if ($quoteId > 0) {
        $items = crm_report_query(
            $db,
            "SELECT g.propid product_id,g.description item_description,g.hsncode,g.rate,g.qty,g.discount,g.gst tax_rate,g.amt
             FROM jos_crm_quotation_grid g WHERE g.qutid={$quoteId} ORDER BY g.id"
        );
        $terms = crm_report_query(
            $db,
            "SELECT term,description FROM jos_crm_quotation_terms WHERE qutid={$quoteId} ORDER BY id"
        );
    } else {
        $items = crm_report_query(
            $db,
            "SELECT DISTINCT g.propid product_id,COALESCE(p.description,'') item_description,
                    COALESCE(p.hsncode,'') hsncode,COALESCE(p.rate,0) rate,1 qty,0 discount,
                    COALESCE(p.cgst,0) tax_rate,0 amt
             FROM jos_crm_leadentry_grid g
             LEFT JOIN jos_crm_crmproducts p ON p.id=g.propid
             WHERE g.leadid={$leadId} AND g.propid>0 ORDER BY g.id"
        );
        $terms = [
            ['term' => 'Payment Terms', 'description' => 'Payment as mutually agreed.'],
            ['term' => 'Quotation Validity', 'description' => 'This quotation is valid for 15 days from the quotation date.'],
            ['term' => 'Taxes', 'description' => 'Taxes are applied as shown against each product.'],
        ];
    }
    if ($items === []) {
        $items[] = ['product_id' => 0, 'item_description' => '', 'hsncode' => '', 'rate' => 0, 'qty' => 1, 'discount' => 0, 'tax_rate' => 0, 'amt' => 0];
    }
} catch (Throwable $exception) {
    $error = $exception->getMessage();
}

$form = [
    'date' => (string)($quote['date'] ?? date('Y-m-d')),
    'status' => (string)($quote['status'] ?? $lead['leadstatus'] ?? ''),
    'gsttype' => (int)($quote['gsttype'] ?? 0),
    'description' => (string)($quote['description'] ?? 'QUOTATION FOR ATTENDANCE BOX - STAFF PAYROLL MANAGEMENT SYSTEM'),
    'descr' => (string)($quote['descr'] ?? 'Thanks for giving us an opportunity to offer our products and services. As discussed, below are the details of our commercial offering.'),
];
$productNamesById = [];
foreach ($products as $product) {
    $productNamesById[(int)$product['id']] = (string)$product['name'];
}

crm_page_start('Generate Quotation', 'operations', $quoteId > 0 ? 'Edit quotation #' . $quoteId : 'Lead #' . $leadId . ' / Commercial Proposal');
?>
<?php if ($error !== ''): ?><div class="report-notice"><i class="fa-solid fa-circle-exclamation"></i><span><?= crm_e($error) ?></span></div><?php endif; ?>
<?php if ($lead !== []): ?>
<form method="post" id="crm-quotation-form">
    <input type="hidden" name="csrf_token" value="<?= crm_e(crm_csrf_token()) ?>">
    <input type="hidden" name="lead_id" value="<?= $leadId ?>">
    <input type="hidden" name="quote_id" value="<?= $quoteId ?>">
    <section class="lead-command-bar">
        <div><strong><?= crm_e((string)$lead['company']) ?></strong><span>Lead #<?= $leadId ?><?= $quoteId > 0 ? ' · Quotation #' . $quoteId : '' ?></span></div>
        <div class="inline-actions">
            <a class="button secondary" href="<?= crm_e(crm_url('operations/leads.php?lead_no=' . $leadId)) ?>">Cancel</a>
            <button class="button primary" type="submit"><i class="fa-solid fa-floppy-disk"></i> Save Quotation</button>
        </div>
    </section>

    <div class="section-stack quote-workspace">
        <section class="card">
            <header class="card-head"><div class="card-title"><i class="fa-solid fa-building"></i><div><h2>Customer and Quote</h2><p>Commercial document details linked to the selected lead.</p></div></div><span class="badge blue">Lead #<?= $leadId ?></span></header>
            <div class="card-body form-grid">
                <div class="field"><label>Company</label><input class="control" value="<?= crm_e((string)$lead['company']) ?>" readonly></div>
                <div class="field"><label>Contact</label><input class="control" value="<?= crm_e(trim((string)$lead['contact_person'] . ' ' . (string)$lead['contact_no'])) ?>" readonly></div>
                <div class="field"><label>Quotation Date</label><input class="control" type="date" name="date" value="<?= crm_e($form['date']) ?>" required></div>
                <div class="field"><label>Lead Status</label><select class="control" name="status" required><option value="">Select status</option><?php foreach ($statuses as $status): ?><option value="<?= (int)$status['id'] ?>" <?= (string)$form['status'] === (string)$status['id'] ? 'selected' : '' ?>><?= crm_e((string)$status['name']) ?></option><?php endforeach; ?></select></div>
                <div class="field wide"><label>GST Type</label><div class="segmented quote-gst-type"><label><input type="radio" name="gsttype" value="0" <?= $form['gsttype'] !== 1 ? 'checked' : '' ?>> CGST + SGST</label><label><input type="radio" name="gsttype" value="1" <?= $form['gsttype'] === 1 ? 'checked' : '' ?>> IGST</label></div></div>
                <div class="field full"><label>Subject</label><textarea class="control textarea compact" name="description" required><?= crm_e($form['description']) ?></textarea></div>
                <div class="field full"><label>Introduction</label><textarea class="control textarea compact" name="descr"><?= crm_e($form['descr']) ?></textarea></div>
            </div>
        </section>

        <section class="card quote-products-card">
            <header class="card-head quote-products-head"><div class="card-title"><i class="fa-solid fa-boxes-stacked"></i><div><h2>Products and Pricing</h2><p>Search products by name. Rates, discount and GST are recalculated when saved.</p></div></div><button class="button small quote-add-product-button" type="button" id="quote-add-row"><i class="fa-solid fa-circle-plus"></i> Add Product</button></header>
            <datalist id="quote-product-options"><?php foreach ($products as $product): ?><option value="<?= crm_e((string)$product['name']) ?>" label="Product #<?= (int)$product['id'] ?>"></option><?php endforeach; ?></datalist>
            <div class="table-wrap quote-items-wrap">
                <table class="data-table quote-items-table">
                    <thead><tr><th>Product / Description</th><th>HSN</th><th>Rate</th><th>Qty</th><th>Discount</th><th>GST %</th><th>Amount</th><th></th></tr></thead>
                    <tbody id="quote-items-body">
                    <?php foreach ($items as $item): ?>
                        <tr class="quote-item-row">
                            <td><div class="quote-product-autocomplete"><i class="fa-solid fa-magnifying-glass"></i><input class="control quote-product-search" list="quote-product-options" value="<?= crm_e($productNamesById[(int)$item['product_id']] ?? '') ?>" placeholder="Type to search product..." autocomplete="off" required><input class="quote-product" name="product_id[]" type="hidden" value="<?= (int)$item['product_id'] ?>"></div><textarea class="control quote-description" name="item_description[]" placeholder="Product description"><?= crm_e((string)$item['item_description']) ?></textarea></td>
                            <td><input class="control quote-hsn" name="hsncode[]" value="<?= crm_e((string)$item['hsncode']) ?>"></td>
                            <td><input class="control quote-rate" name="rate[]" type="number" min="0" step="0.01" value="<?= crm_e((string)$item['rate']) ?>"></td>
                            <td><input class="control quote-qty" name="qty[]" type="number" min="0.01" step="0.01" value="<?= crm_e((string)$item['qty']) ?>"></td>
                            <td><input class="control quote-discount" name="discount[]" type="number" min="0" step="0.01" value="<?= crm_e((string)$item['discount']) ?>"></td>
                            <td><input class="control quote-tax" name="tax_rate[]" type="number" min="0" max="100" step="0.01" value="<?= crm_e((string)$item['tax_rate']) ?>"></td>
                            <td><output class="quote-line-total"><?= number_format((float)$item['amt'], 2) ?></output></td>
                            <td><button class="icon-button quote-remove-row" type="button" aria-label="Remove product"><i class="fa-solid fa-trash"></i></button></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
            <div class="quote-totals">
                <div><span>Subtotal</span><strong id="quote-subtotal">₹0.00</strong></div>
                <div><span>GST</span><strong id="quote-gst">₹0.00</strong></div>
                <div class="grand"><span>Total Amount</span><strong id="quote-total">₹0.00</strong></div>
            </div>
        </section>

        <section class="card">
            <header class="card-head"><div class="card-title"><i class="fa-solid fa-list-check"></i><div><h2>Terms and Conditions</h2><p>Add the commercial terms that will print on the quotation.</p></div></div><button class="button secondary small" type="button" id="quote-add-term"><i class="fa-solid fa-plus"></i> Add Term</button></header>
            <div class="card-body quote-terms" id="quote-terms">
                <?php foreach ($terms as $term): ?><div class="quote-term-row"><input class="control" name="term[]" value="<?= crm_e((string)$term['term']) ?>" placeholder="Term title"><textarea class="control" name="condition[]" placeholder="Description"><?= crm_e((string)$term['description']) ?></textarea><button class="icon-button quote-remove-term" type="button" aria-label="Remove term"><i class="fa-solid fa-trash"></i></button></div><?php endforeach; ?>
            </div>
        </section>
    </div>
</form>

<template id="quote-row-template">
    <tr class="quote-item-row">
        <td><div class="quote-product-autocomplete"><i class="fa-solid fa-magnifying-glass"></i><input class="control quote-product-search" list="quote-product-options" placeholder="Type to search product..." autocomplete="off" required><input class="quote-product" name="product_id[]" type="hidden" value=""></div><textarea class="control quote-description" name="item_description[]" placeholder="Product description"></textarea></td>
        <td><input class="control quote-hsn" name="hsncode[]"></td><td><input class="control quote-rate" name="rate[]" type="number" min="0" step="0.01" value="0"></td><td><input class="control quote-qty" name="qty[]" type="number" min="0.01" step="0.01" value="1"></td><td><input class="control quote-discount" name="discount[]" type="number" min="0" step="0.01" value="0"></td><td><input class="control quote-tax" name="tax_rate[]" type="number" min="0" max="100" step="0.01" value="0"></td><td><output class="quote-line-total">0.00</output></td><td><button class="icon-button quote-remove-row" type="button" aria-label="Remove product"><i class="fa-solid fa-trash"></i></button></td>
    </tr>
</template>
<script>
(() => {
    const body = document.getElementById('quote-items-body');
    const rowTemplate = document.getElementById('quote-row-template');
    const products = <?= json_encode(array_map(static fn(array $product): array => [
        'id' => (int)$product['id'],
        'name' => (string)$product['name'],
        'description' => (string)$product['description'],
        'hsn' => (string)$product['hsncode'],
        'rate' => (float)$product['rate'],
        'cgst' => (float)$product['cgst'],
        'igst' => (float)$product['igst'],
    ], $products), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
    const productsByName = new Map(products.map(product => [product.name.trim().toLocaleLowerCase(), product]));
    const productsById = new Map(products.map(product => [String(product.id), product]));
    const gstType = () => document.querySelector('input[name="gsttype"]:checked')?.value || '0';
    const money = value => `₹${Number(value || 0).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`;
    const calculate = () => {
        let subtotal = 0, gst = 0, total = 0;
        body.querySelectorAll('.quote-item-row').forEach(row => {
            const rate = Math.max(0, Number(row.querySelector('.quote-rate').value) || 0);
            const qty = Math.max(0, Number(row.querySelector('.quote-qty').value) || 0);
            const discount = Math.min(Math.max(0, Number(row.querySelector('.quote-discount').value) || 0), rate * qty);
            const taxRate = Math.min(100, Math.max(0, Number(row.querySelector('.quote-tax').value) || 0));
            const taxable = (rate * qty) - discount;
            const tax = taxable * taxRate / 100;
            const amount = taxable + tax;
            subtotal += taxable; gst += tax; total += amount;
            row.querySelector('.quote-line-total').textContent = amount.toFixed(2);
        });
        document.getElementById('quote-subtotal').textContent = money(subtotal);
        document.getElementById('quote-gst').textContent = money(gst);
        document.getElementById('quote-total').textContent = money(total);
    };
    const wireRow = row => {
        const productId = row.querySelector('.quote-product');
        const productSearch = row.querySelector('.quote-product-search');
        const applyProduct = () => {
            const typedName = productSearch.value.trim();
            const selected = productsByName.get(typedName.toLocaleLowerCase());
            productId.value = selected ? selected.id : '';
            productSearch.setCustomValidity(typedName !== '' && !selected ? 'Choose a product from the suggestions.' : '');
            if (!selected) {
                if (typedName === '') productSearch.setCustomValidity('Select a product.');
                return;
            }
            productSearch.setCustomValidity('');
            row.querySelector('.quote-description').value = selected.description || '';
            row.querySelector('.quote-hsn').value = selected.hsn || '';
            row.querySelector('.quote-rate').value = selected.rate || 0;
            row.querySelector('.quote-tax').value = gstType() === '1' ? (selected.igst || 0) : (selected.cgst || 0);
            calculate();
        };
        productSearch.addEventListener('input', applyProduct);
        productSearch.addEventListener('change', applyProduct);
        row.querySelectorAll('input').forEach(input => input.addEventListener('input', calculate));
        row.querySelector('.quote-remove-row').addEventListener('click', () => {
            if (body.querySelectorAll('.quote-item-row').length > 1) row.remove();
            else {
                row.querySelectorAll('input,textarea,select').forEach(input => input.value = input.classList.contains('quote-qty') ? 1 : '');
                row.querySelector('.quote-product-search').setCustomValidity('');
            }
            calculate();
        });
    };
    body.querySelectorAll('.quote-item-row').forEach(wireRow);
    document.getElementById('quote-add-row').addEventListener('click', () => {
        const row = rowTemplate.content.firstElementChild.cloneNode(true); body.appendChild(row); wireRow(row); row.querySelector('.quote-product-search').focus();
    });
    document.querySelectorAll('input[name="gsttype"]').forEach(input => input.addEventListener('change', () => {
        body.querySelectorAll('.quote-item-row').forEach(row => {
            const product = productsById.get(row.querySelector('.quote-product').value);
            if (product) row.querySelector('.quote-tax').value = gstType() === '1' ? (product.igst || 0) : (product.cgst || 0);
        }); calculate();
    }));
    document.getElementById('quote-add-term').addEventListener('click', () => {
        const row = document.createElement('div'); row.className = 'quote-term-row';
        row.innerHTML = '<input class="control" name="term[]" placeholder="Term title"><textarea class="control" name="condition[]" placeholder="Description"></textarea><button class="icon-button quote-remove-term" type="button" aria-label="Remove term"><i class="fa-solid fa-trash"></i></button>';
        document.getElementById('quote-terms').appendChild(row); row.querySelector('input').focus();
    });
    document.getElementById('quote-terms').addEventListener('click', event => { const button = event.target.closest('.quote-remove-term'); if (button) button.closest('.quote-term-row').remove(); });
    calculate();
})();
</script>
<?php endif; ?>
<?php crm_page_end(); ?>
