<?php //ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL);
// includes/finance/finance_quotes_functions.php

// Include tenant config
if (file_exists('../../../../' . $_REQUEST['tenant'] . '/config.php')) {
    require_once('../../../../' . $_REQUEST['tenant'] . '/config.php');
}
if (file_exists('/config.php')) {
    require_once('/config.php');
}

header('Content-Type: application/json; charset=utf-8');

if (!isset($_REQUEST['FUNCTION'])) {
    echo json_encode(['status' => 'error', 'message' => 'No FUNCTION specified']);
    exit;
}

$func = $_REQUEST['FUNCTION'];

// Basic guard: ensure DB handle exists
if (!isset($GLOBALS['con']) || !$GLOBALS['con'] instanceof mysqli) {
    echo json_encode(['status' => 'error', 'message' => 'Database connection not available']);
    exit;
}

/**
 * Generate next quote reference QYYNNNN style.
 */
function generateQuoteRef(mysqli $con): string
{
    $year = date('y'); // 25 for 2025
    $prefix = 'Q' . $year;

    $stmt = $con->prepare("SELECT quote_ref FROM finance_quotes WHERE quote_ref LIKE CONCAT(?, '%') ORDER BY id DESC LIMIT 1");
    $stmt->bind_param('s', $prefix);
    $stmt->execute();
    $res = $stmt->get_result();
    $last = $res->fetch_assoc();
    $stmt->close();

    $nextNumber = 1;
    if ($last && isset($last['quote_ref'])) {
        // quote_ref format: QYYNNNN
        $suffix = substr($last['quote_ref'], 3); // after QYY
        if (ctype_digit($suffix)) {
            $nextNumber = (int)$suffix + 1;
        }
    }

    return sprintf('%s%04d', $prefix, $nextNumber);
}

/**
 * Generate a random public token.
 */
function generatePublicToken(): string
{
    return bin2hex(random_bytes(16));
}

/**
 * Calculate totals from items array.
 * Each item: ['qty','unit_price','vatrate']
 */
function calculateTotals(array $items, float $vatrate): array
{
    $netTotal  = 0.0;
    $vatTotal  = 0.0;
    $grossTotal = 0.0;
    $rate = $vatrate / 100.0;

    foreach ($items as &$item) {
        $qty        = isset($item['qty']) ? (float)$item['qty'] : 0.0;
        $unit_price = isset($item['unit_price']) ? (float)$item['unit_price'] : 0.0;
        $net        = $qty * $unit_price;
        $vat        = round($net * $rate, 2);
        $gross      = $net + $vat;

        $item['net']   = $net;
        $item['vat']   = $vat;
        $item['gross'] = $gross;

        $netTotal   += $net;
        $vatTotal   += $vat;
        $grossTotal += $gross;
    }
    unset($item);

    return [
        'items'      => $items,
        'net_total'  => round($netTotal, 2),
        'vat_total'  => round($vatTotal, 2),
        'gross_total' => round($grossTotal, 2),
    ];
}

/**
 * Save or update a quote (header + items).
 */
function saveQuote(): void
{
    $con = $GLOBALS['con'];
    $quoteId      = isset($_POST['quote_id']) ? (int)$_POST['quote_id'] : 0;
    $quoteRef = null;
    if ($quoteId > 0) {
        $q = $con->prepare("SELECT quote_ref FROM finance_quotes WHERE id=?");
        $q->bind_param('i', $quoteId);
        $q->execute();
        $qr = $q->get_result()->fetch_assoc();
        $q->close();
        if ($qr) {
            $quoteRef = $qr['quote_ref'];
        }
    }
    $clientMode   = $_POST['client_mode'] ?? 'new_contact';
    $clientnumber = !empty($_POST['clientnumber']) ? (int)$_POST['clientnumber'] : null;

    $iuMinutes = isset($_POST['iu_minutes_per_unit']) ? (int)$_POST['iu_minutes_per_unit'] : 15;
    $iuRate    = isset($_POST['iu_rate_per_unit']) ? (float)$_POST['iu_rate_per_unit'] : 0.0;

    $scopeType    = $_POST['scope_type'] ?? 'single';
    $sourceType   = $_POST['source_type'] ?? 'manual';

    $contactName    = $_POST['contact_name'] ?? '';
    $contactCompany = $_POST['contact_company'] ?? '';
    $contactEmail   = $_POST['contact_email'] ?? '';
    $contactPhone   = $_POST['contact_phone'] ?? '';
    $billingAddress = $_POST['billing_address'] ?? '';

    $vatrate   = isset($_POST['vatrate']) ? (float)$_POST['vatrate'] : 20.0;

    $validUntilTs = !empty($_POST['valid_until'])
        ? (int)$_POST['valid_until']
        : null; // JS must send unix timestamp if used

    $notesInternal = $_POST['notes_internal'] ?? '';
    $notesClient   = $_POST['notes_client'] ?? '';

    $createdBy = $_POST['created_by'] ?? ($_SESSION['admin_id'] ?? 'system');

    $itemsJson = $_POST['items'] ?? '[]';
    $items     = json_decode($itemsJson, true);

    if (!is_array($items)) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid items payload']);
        return;
    }

    $calc = calculateTotals($items, $vatrate);
    $items = $calc['items'];

    $now = time();

    if ($quoteId <= 0) {
        // Insert
        $quoteRef    = generateQuoteRef($con);
        $publicToken = generatePublicToken();


        $vatrateStr = (string)$vatrate;

        $stmt = $con->prepare("
    INSERT INTO finance_quotes
    (quote_ref, version, public_token,
     client_mode, clientnumber,
     contact_name, contact_company, contact_email, contact_phone, billing_address,
     scope_type, source_type,
     status, valid_until, date_created,
     net_total, vat_total, gross_total, vatrate, currency,
     notes_internal, notes_client,
     created_by)
    VALUES
    (?, 1, ?,
     ?, ?,
     ?, ?, ?, ?, ?,
     ?, ?,
     'draft', ?, ?,
     ?, ?, ?, ?, ?,
     ?, ?,
     ?)
");

        $stmt->bind_param(
            // 21 params → 21 chars:
            // s,s,s,i,s,s,s,s,s,s,s,i,i,d,d,d,s,s,s,s,s
            'sssisssssssiidddssss',
            $quoteRef,          // s
            $publicToken,       // s
            $clientMode,        // s
            $clientnumber,      // i
            $contactName,       // s
            $contactCompany,    // s
            $contactEmail,      // s
            $contactPhone,      // s
            $billingAddress,    // s
            $scopeType,         // s
            $sourceType,        // s
            $validUntilTs,      // i
            $now,               // i
            $calc['net_total'], // d
            $calc['vat_total'], // d
            $calc['gross_total'], // d
            $vatrateStr,        // s (VARCHAR(4))
            $notesInternal,     // s
            $notesClient,       // s
            $createdBy          // s
        );


        if (!$stmt->execute()) {
            $err = $stmt->error;
            $stmt->close();
            echo json_encode(['status' => 'error', 'message' => 'Failed to create quote: ' . $err]);
            return;
        }
        $quoteId = $stmt->insert_id;
        $stmt->close();
    } else {
        // Update
        $stmt = $con->prepare("
    UPDATE finance_quotes
    SET client_mode=?, clientnumber=?,
        contact_name=?, contact_company=?, contact_email=?, contact_phone=?, billing_address=?,
        scope_type=?, source_type=?,
        valid_until=?, net_total=?, vat_total=?, gross_total=?, vatrate=?, currency=?,
        notes_internal=?, notes_client=?,
        updated_by=?, updated_at=?
    WHERE id=? AND is_deleted=0
");

        $stmt->bind_param(
            'sisssssssiddddissii',
            $clientMode,
            $clientnumber,
            $contactName,
            $contactCompany,
            $contactEmail,
            $contactPhone,
            $billingAddress,
            $scopeType,
            $sourceType,
            $validUntilTs,
            $calc['net_total'],
            $calc['vat_total'],
            $calc['gross_total'],
            $vatrate,
            $notesInternal,
            $notesClient,
            $createdBy,
            $now,
            $quoteId
        );


        if (!$stmt->execute()) {
            $err = $stmt->error;
            $stmt->close();
            echo json_encode(['status' => 'error', 'message' => 'Failed to update quote: ' . $err]);
            return;
        }
        $stmt->close();

        // Remove existing items, we'll reinsert
        $del = $con->prepare("DELETE FROM finance_quote_items WHERE quote_id=?");
        $del->bind_param('i', $quoteId);
        $del->execute();
        $del->close();
    }

    // Insert items
    if (!empty($items)) {
        $ins = $con->prepare("
            INSERT INTO finance_quote_items
            (quote_id, line_no, item_type, description, qty, unit_price, net, vat, gross, meta)
            VALUES
            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ");

        $lineNo = 1;
        foreach ($items as $item) {
            $itemType    = $item['item_type'] ?? 'inspection';
            $desc        = $item['description'] ?? '';
            $qty         = (float)($item['qty'] ?? 0);
            $unitPrice   = (float)($item['unit_price'] ?? 0);
            $net         = (float)($item['net'] ?? 0);
            $vat         = (float)($item['vat'] ?? 0);
            $gross       = (float)($item['gross'] ?? 0);
            $meta        = isset($item['meta']) ? json_encode($item['meta']) : null;

            $ins->bind_param(
                'iissddddds',
                $quoteId,
                $lineNo,
                $itemType,
                $desc,
                $qty,
                $unitPrice,
                $net,
                $vat,
                $gross,
                $meta
            );
            $ins->execute();
            $lineNo++;
        }
        $ins->close();
    }

    echo json_encode([
        'status'          => 'success',
        'message'         => 'Quote saved successfully',
        'quote_id'        => $quoteId,
        'quote_ref'       => $quoteRef,
        'client_mode'     => $clientMode,
        'clientnumber'    => $clientnumber,
        'contact_company' => $contactCompany,
        'contact_name'    => $contactName,
        'contact_email'   => $contactEmail,
    ]);
}

/**
 * List quotes (basic listing, can be extended with filters).
 */
function listQuotes(): void
{
    $con = $GLOBALS['con'];

    $where = " WHERE is_deleted=0 ";
    $params = [];
    $types  = '';

    if (!empty($_GET['status']) && $_GET['status'] !== 'all') {
        $where .= " AND status=? ";
        $types .= 's';
        $params[] = $_GET['status'];
    }

    if (!empty($_GET['clientnumber'])) {
        $where .= " AND clientnumber=? ";
        $types .= 'i';
        $params[] = (int)$_GET['clientnumber'];
    }

    $sql = "
        SELECT q.*, c.clientname
        FROM finance_quotes q
        LEFT JOIN clientdetails c ON q.clientnumber = c.clientnumber
        $where
        ORDER BY q.date_created DESC
    ";

    if ($types) {
        $stmt = $con->prepare($sql);
        $stmt->bind_param($types, ...$params);
        $stmt->execute();
        $res = $stmt->get_result();
    } else {
        $res = $con->query($sql);
    }

    $rows = [];
    while ($row = $res->fetch_assoc()) {
        $rows[] = [
            'id'          => (int)$row['id'],
            'quote_ref'   => $row['quote_ref'],
            'client_mode' => $row['client_mode'],
            'clientname'  => $row['clientname'] ?: $row['contact_company'],
            'contact_name' => $row['contact_name'],
            'scope_type'  => $row['scope_type'],
            'source_type' => $row['source_type'],
            'status'      => $row['status'],
            'date_created' => (int)$row['date_created'],
            'valid_until' => $row['valid_until'] ? (int)$row['valid_until'] : null,
            'gross_total' => (float)$row['gross_total'],
        ];
    }

    if (isset($stmt) && $stmt instanceof mysqli_stmt) {
        $stmt->close();
    }

    echo json_encode(['status' => 'success', 'data' => $rows]);
}

/**
 * Get a single quote with items.
 */
function getQuote(): void
{
    $con = $GLOBALS['con'];
    $id  = isset($_GET['quote_id']) ? (int)$_GET['quote_id'] : 0;

    if ($id <= 0) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid quote id']);
        return;
    }

    $stmt = $con->prepare("SELECT * FROM finance_quotes WHERE id=? AND is_deleted=0");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $res = $stmt->get_result();
    $quote = $res->fetch_assoc();
    $stmt->close();

    if (!$quote) {
        echo json_encode(['status' => 'error', 'message' => 'Quote not found']);
        return;
    }

    $itemsRes = $con->prepare("SELECT * FROM finance_quote_items WHERE quote_id=? ORDER BY line_no ASC");
    $itemsRes->bind_param('i', $id);
    $itemsRes->execute();
    $itemsResult = $itemsRes->get_result();
    $items = [];
    while ($row = $itemsResult->fetch_assoc()) {
        $row['qty']        = (float)$row['qty'];
        $row['unit_price'] = (float)$row['unit_price'];
        $row['net']        = (float)$row['net'];
        $row['vat']        = (float)$row['vat'];
        $row['gross']      = (float)$row['gross'];
        $row['meta']       = $row['meta'] ? json_decode($row['meta'], true) : null;
        $items[] = $row;
    }
    $itemsRes->close();

    echo json_encode([
        'status' => 'success',
        'quote'  => $quote,
        'items'  => $items
    ]);
}

/**
 * Soft delete a quote.
 */
function deleteQuote(): void
{
    $con = $GLOBALS['con'];
    $id  = isset($_POST['quote_id']) ? (int)$_POST['quote_id'] : 0;

    if ($id <= 0) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid quote id']);
        return;
    }

    $stmt = $con->prepare("UPDATE finance_quotes SET status='deleted', is_deleted=1 WHERE id=?");
    $stmt->bind_param('i', $id);
    if (!$stmt->execute()) {
        $err = $stmt->error;
        $stmt->close();
        echo json_encode(['status' => 'error', 'message' => 'Failed to delete quote: ' . $err]);
        return;
    }
    $stmt->close();

    echo json_encode(['status' => 'success', 'message' => 'Quote deleted']);
}

/**
 * Update status (sent, accepted, rejected, expired, converted).
 */
function updateStatus(): void
{
    $con    = $GLOBALS['con'];
    $id     = isset($_POST['quote_id']) ? (int)$_POST['quote_id'] : 0;
    $status = $_POST['status'] ?? '';

    if ($id <= 0 || $status === '') {
        echo json_encode(['status' => 'error', 'message' => 'Invalid parameters']);
        return;
    }

    $now = time();
    $sql = "UPDATE finance_quotes SET status=?, updated_at=?";

    if ($status === 'sent') {
        $sql .= ", date_sent=?";
    } elseif (in_array($status, ['accepted', 'rejected'], true)) {
        $sql .= ", date_responded=?";
    }

    $sql .= " WHERE id=? AND is_deleted=0";

    if ($status === 'sent' || in_array($status, ['accepted', 'rejected'], true)) {
        $stmt = $con->prepare($sql);
        $stmt->bind_param('siii', $status, $now, $now, $id);
    } else {
        $stmt = $con->prepare($sql);
        $stmt->bind_param('sii', $status, $now, $id);
    }

    if (!$stmt->execute()) {
        $err = $stmt->error;
        $stmt->close();
        echo json_encode(['status' => 'error', 'message' => 'Failed to update status: ' . $err]);
        return;
    }
    $stmt->close();

    echo json_encode(['status' => 'success', 'message' => 'Status updated']);
}

function buildItemsFromClient(): void
{
    $con = $GLOBALS['con'];

    // Clientnumber from request
    $clientnumber = 0;
    if (isset($_REQUEST['clientnumber'])) {
        $clientnumber = (int)$_REQUEST['clientnumber'];
    }

    if ($clientnumber <= 0) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid client number.']);
        return;
    }

    // === TEMP CONFIG – these will move into clientdetails later ===
    // 1 IU = X minutes
    $IU_MINUTES = 15;

    // Cost per IU (e.g. £5.00)
    $IU_COST = 25.00;

    // === Fetch client rate_per_hour for comparison ===
    $ratePerHourNumeric = 0.0;
    $rateSql = "
        SELECT rate_per_hour
        FROM clientdetails
        WHERE clientnumber = ? AND statuslive = 1
        LIMIT 1
    ";
    if ($stmtRate = $con->prepare($rateSql)) {
        $stmtRate->bind_param('i', $clientnumber);
        $stmtRate->execute();
        $resRate = $stmtRate->get_result();
        if ($rowRate = $resRate->fetch_assoc()) {
            $rateRaw = (string)($rowRate['rate_per_hour'] ?? '');
            // Strip non-numeric, handle values like "£85/hr"
            $rateRaw = preg_replace('/[^0-9.\-]/', '', $rateRaw);
            if ($rateRaw !== '') {
                $ratePerHourNumeric = (float)$rateRaw;
            }
        }
        $stmtRate->close();
    }

    // === Collate active items grouped by desc+code and pull IU from dd_plant ===
    $sql = "
        SELECT
            i.`desc`             AS item_desc,
            i.`code`             AS item_code,
            COUNT(*)             AS item_count,
            COALESCE(p.units, 0) AS units_per_item
        FROM itemdetails i
        LEFT JOIN dd_plant p ON p.code = i.code
        WHERE i.clientnumber = ?
          AND i.statuslive = 1
        GROUP BY i.`desc`, i.`code`, p.units
        ORDER BY i.`desc` ASC, i.`code` ASC
    ";

    if (!($stmt = $con->prepare($sql))) {
        echo json_encode(['status' => 'error', 'message' => 'Failed to prepare item query.']);
        return;
    }

    $stmt->bind_param('i', $clientnumber);
    $stmt->execute();
    $res = $stmt->get_result();

    $items      = [];
    $totalUnits = 0.0;
    $totalItems = 0;

    while ($row = $res->fetch_assoc()) {
        $desc         = $row['item_desc'] ?? '';
        $code         = $row['item_code'] ?? '';
        $count        = (int)($row['item_count'] ?? 0);
        $unitsPerItem = (float)($row['units_per_item'] ?? 0.0);

        if ($count <= 0) {
            continue;
        }

        // Total IU for this group
        $groupUnits = $unitsPerItem * $count;
        $totalUnits += $groupUnits;
        $totalItems += $count;

        // Cost per item and line total based on IU cost
        $perItemCost = $unitsPerItem * $IU_COST;
        $lineNet     = $perItemCost * $count;

        // Line description
        $lineDesc = trim($desc) !== '' ? $desc : '(Unspecified description)';
        if ($code !== '') {
            $lineDesc .= " (Code: {$code})";
        }
        if ($unitsPerItem > 0) {
            $lineDesc .= " – {$unitsPerItem} IU per item";
        }

        $items[] = [
            'item_type'   => 'ui_item',
            'description' => $lineDesc,
            'qty'         => $count,
            'unit_price'  => round($perItemCost, 2),
            // net/vat/gross will be recalculated in JS based on the current VAT rate,
            // but send sensible defaults so the UI doesn't look empty.
            'net'         => round($lineNet, 2),
            'vat'         => 0,
            'gross'       => round($lineNet, 2),
            // extra metadata if you want it later
            'units_per_item' => $unitsPerItem,
            'total_units'    => $groupUnits,
            'code'           => $code,
            'raw_desc'       => $desc,
            'item_count'     => $count,
        ];
    }

    $stmt->close();

    if (!$items) {
        echo json_encode([
            'status'  => 'success',
            'items'   => [],
            'summary' => null,
            'message' => 'No active items found for this client.'
        ]);
        return;
    }

    // === IU totals, time, and costs ===
    $totalMinutes = $totalUnits * $IU_MINUTES;
    $totalHours   = $totalMinutes / 60.0;

    $estTotalCost = $totalUnits * $IU_COST;

    $estAtRate = 0.0;
    if ($ratePerHourNumeric > 0) {
        $estAtRate = $totalHours * $ratePerHourNumeric;
    }

    $summary = [
        'total_items'       => $totalItems,
        'total_units'       => $totalUnits,
        'iu_minutes'        => $IU_MINUTES,
        'total_minutes'     => $totalMinutes,
        'total_hours'       => $totalHours,
        'iu_cost'           => $IU_COST,
        'est_total_cost'    => $estTotalCost,
        'rate_per_hour'     => $ratePerHourNumeric,
        'est_at_hour_rate'  => $estAtRate,
    ];

    echo json_encode([
        'status'  => 'success',
        'items'   => $items,
        'summary' => $summary
    ]);
}


// Dispatch
switch ($func) {
    case 'saveQuote':
        saveQuote();
        break;
    case 'listQuotes':
        listQuotes();
        break;
    case 'getQuote':
        getQuote();
        break;
    case 'deleteQuote':
        deleteQuote();
        break;
    case 'updateStatus':
        updateStatus();
        break;
    case 'buildItemsFromClient':
        buildItemsFromClient();
        break;
    case 'getClientDetails':
        getClientDetails();
        break;
    default:
        echo json_encode(['status' => 'error', 'message' => 'Unknown FUNCTION']);
        break;
}

function getClientDetails(): void
{
    $con          = $GLOBALS['con'];
    $clientnumber = isset($_GET['clientnumber']) ? (int)$_GET['clientnumber'] : 0;

    if ($clientnumber <= 0) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid client number']);
        return;
    }

    $sql = "
        SELECT
            clientname,
            phone1,
            email,
            pri_contact_name,
            pri_contact_tel,
            pri_contact_email,

            billing_name,
            billing1,
            billing2,
            billing_town,
            billing_county,
            billing_postcode,
            billing_email,
            billing_phone,

            address1,
            address2,
            town,
            county,
            postcode
        FROM clientdetails
        WHERE clientnumber = ?
          AND statuslive = 1
        LIMIT 1
    ";

    if (!($stmt = $con->prepare($sql))) {
        echo json_encode(['status' => 'error', 'message' => 'Failed to prepare client query']);
        return;
    }

    $stmt->bind_param('i', $clientnumber);
    $stmt->execute();
    $res = $stmt->get_result();
    $row = $res->fetch_assoc();
    $stmt->close();

    if (!$row) {
        echo json_encode(['status' => 'error', 'message' => 'Client not found or not active']);
        return;
    }

    // Company name: prefer billing_name, fall back to clientname
    $contactCompany = $row['billing_name'] ?: $row['clientname'];

    // Contact name: use primary contact if present
    $contactName = $row['pri_contact_name'] ?: '';

    // Email: prefer billing_email, then primary contact, then main email
    $contactEmail = $row['billing_email']
        ?: ($row['pri_contact_email'] ?: $row['email']);

    // Phone: prefer billing_phone, then primary contact tel, then phone1
    $contactPhone = $row['billing_phone']
        ?: ($row['pri_contact_tel'] ?: $row['phone1']);

    // Billing address: prefer billing_*; if mostly empty, fall back to main address
    $billingParts = [];
    foreach (['billing1', 'billing2', 'billing_town', 'billing_county', 'billing_postcode'] as $key) {
        if (!empty($row[$key]) && $row[$key] !== '0') {
            $billingParts[] = $row[$key];
        }
    }

    if (empty($billingParts)) {
        foreach (['address1', 'address2', 'town', 'county', 'postcode'] as $key) {
            if (!empty($row[$key])) {
                $billingParts[] = $row[$key];
            }
        }
    }

    $billingAddress = implode("\n", $billingParts);

    echo json_encode([
        'status' => 'success',
        'data'   => [
            'contact_company' => $contactCompany ?: '',
            'contact_name'    => $contactName ?: '',
            'contact_email'   => $contactEmail ?: '',
            'contact_phone'   => $contactPhone ?: '',
            'billing_address' => $billingAddress ?: '',
        ]
    ]);
}
