<?php
/**
 * ============================================================
 *  বধুবরণ জুয়েলার্স ERP — Sales Module
 *  File: api/sales/create_sale.php
 *  v4 (2026-06-05): গ্রাহক auto-save to parties table
 *
 *  পুরো sale একটা atomic transaction-এ create করে:
 *   1) Invoice number auto-generate
 *   2) গ্রাহক auto-save/find (parties table)
 *   3) sales table-এ master row
 *   4) sale_items + stock কমানো (barcode/new_stock)
 *   5) sale_exchanges (পুরনো সোনা)
 *   6) sale_payments + cash_transactions (multi-account, helper দিয়ে)
 * ============================================================
 */

require_once __DIR__ . '/../_core.php';
require_once __DIR__ . '/../_finance.php';
header('Content-Type: application/json; charset=utf-8');

if (!is_logged_in()) {
    http_response_code(401);
    echo json_encode(['ok' => false, 'error' => 'লগইন করুন আগে']);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['ok' => false, 'error' => 'POST only']);
    exit;
}

$raw   = file_get_contents('php://input');
$input = json_decode($raw, true);
if (!is_array($input)) $input = $_POST;

$customer_id         = isset($input['customer_id']) && $input['customer_id'] !== '' ? (int)$input['customer_id'] : null;
$customer_name       = trim($input['customer_name']  ?? '');
$customer_phone      = trim($input['customer_phone'] ?? '');
$sale_date           = $input['sale_date'] ?? date('Y-m-d H:i:s');
$items               = $input['items']     ?? [];
$exchanges           = $input['exchanges'] ?? [];
$payments            = $input['payments']  ?? [];
$making_charge_total = (float)($input['making_charge_total'] ?? 0);
$vat_percent         = (float)($input['vat_percent']         ?? 0);
$discount_amount     = (float)($input['discount_amount']     ?? 0);
$notes               = trim($input['notes'] ?? '');
$user_id             = $_SESSION['user_id'] ?? null;

if (empty($items)) {
    echo json_encode(['ok' => false, 'error' => 'কমপক্ষে একটি item দিন']);
    exit;
}
if (empty($payments)) {
    echo json_encode(['ok' => false, 'error' => 'কমপক্ষে একটি payment দিন']);
    exit;
}

try {
    $pdo->beginTransaction();

    // ============================================================
    // 1) Subtotals calculate
    // ============================================================
    $items_subtotal = 0.0;
    foreach ($items as $it) {
        $items_subtotal += (float)($it['item_total'] ?? 0);
    }

    $exchange_value       = 0.0;
    $exchange_total_grams = 0.0;
    foreach ($exchanges as $ex) {
        $exchange_value       += (float)($ex['exchange_value']    ?? 0);
        $exchange_total_grams += (float)($ex['gross_weight_gram'] ?? 0);
    }

    $vat_amount  = ($items_subtotal + $making_charge_total) * ($vat_percent / 100);
    $grand_total = $items_subtotal + $making_charge_total + $vat_amount
                 - $discount_amount - $exchange_value;
    if ($grand_total < 0) $grand_total = 0;

    $paid_total = 0.0;
    foreach ($payments as $p) {
        $paid_total += (float)($p['amount'] ?? 0);
    }
    $due_amount = max(0, $grand_total - $paid_total);

    if ($due_amount > 0.01) {
        $payment_status = ($paid_total > 0.01) ? 'partial' : 'due';
    } else {
        $payment_status = 'paid';
    }

    // ============================================================
    // 2) গ্রাহক auto-save / find (parties table)
    //    Priority:
    //      a) customer_id দেওয়া থাকলে → সেটাই ব্যবহার করো
    //      b) phone দেওয়া থাকলে → phone দিয়ে খোঁজো
    //         - পাওয়া গেলে → সেই id নাও (নাম update করো)
    //         - না পাওয়া গেলে → নতুন INSERT করো
    //      c) শুধু নাম দেওয়া থাকলে (phone নেই) → নতুন INSERT করো
    //      d) কিছুই না থাকলে → customer_id = null রাখো
    // ============================================================
    $party_auto_saved = false;

    if (!$customer_id && $customer_name !== '') {

        if ($customer_phone !== '') {
            // Phone দিয়ে খোঁজো
            $findStmt = $pdo->prepare(
                "SELECT id FROM parties WHERE phone = ? AND deleted_at IS NULL LIMIT 1"
            );
            $findStmt->execute([$customer_phone]);
            $existingId = $findStmt->fetchColumn();

            if ($existingId) {
                // আছে → নাম update করো (যদি আলাদা হয়)
                $customer_id = (int)$existingId;
                $pdo->prepare(
                    "UPDATE parties SET name = ? WHERE id = ? AND deleted_at IS NULL"
                )->execute([$customer_name, $customer_id]);
            } else {
                // নেই → নতুন তৈরি করো
                $insStmt = $pdo->prepare("
                    INSERT INTO parties (name, phone, is_customer, is_supplier, is_pledge, is_locker, is_karigar)
                    VALUES (?, ?, 1, 0, 0, 0, 0)
                ");
                $insStmt->execute([$customer_name, $customer_phone]);
                $customer_id    = (int)$pdo->lastInsertId();
                $party_auto_saved = true;
            }

        } else {
            // Phone নেই, শুধু নাম → নতুন INSERT (duplicate হতে পারে, ঠিক আছে)
            $insStmt = $pdo->prepare("
                INSERT INTO parties (name, phone, is_customer, is_supplier, is_pledge, is_locker, is_karigar)
                VALUES (?, NULL, 1, 0, 0, 0, 0)
            ");
            $insStmt->execute([$customer_name]);
            $customer_id      = (int)$pdo->lastInsertId();
            $party_auto_saved = true;
        }
    }

    // ============================================================
    // 3) Invoice number generate (auto, per year)
    // ============================================================
    $year = (int)date('Y', strtotime($sale_date));
    $pdo->prepare("INSERT INTO sale_invoice_sequence (year, last_number)
                   VALUES (?, 1)
                   ON DUPLICATE KEY UPDATE last_number = last_number + 1")
        ->execute([$year]);
    $stmt = $pdo->prepare("SELECT last_number FROM sale_invoice_sequence WHERE year = ?");
    $stmt->execute([$year]);
    $seq        = (int)$stmt->fetchColumn();
    $invoice_no = sprintf('INV-%d-%04d', $year, $seq);

    // ============================================================
    // 4) Master sales row
    // ============================================================
    $stmt = $pdo->prepare("
        INSERT INTO sales (
            invoice_no, sale_date, customer_id,
            customer_name_snapshot, customer_phone_snapshot,
            items_subtotal, making_charge_total, vat_percent, vat_amount, discount_amount,
            exchange_total_grams, exchange_value,
            grand_total, paid_total, due_amount, payment_status,
            notes, created_by
        ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
    ");
    $stmt->execute([
        $invoice_no, $sale_date, $customer_id,
        $customer_name, $customer_phone,
        $items_subtotal, $making_charge_total, $vat_percent, $vat_amount, $discount_amount,
        $exchange_total_grams, $exchange_value,
        $grand_total, $paid_total, $due_amount, $payment_status,
        $notes, $user_id
    ]);
    $sale_id = (int)$pdo->lastInsertId();

    // ============================================================
    // 5) Sale items + stock update
    // ============================================================
    $itemStmt = $pdo->prepare("
        INSERT INTO sale_items (
            sale_id, source_type, barcode_stock_id, new_stock_id,
            product_name, category, barcode,
            karat, purity_percent,
            gross_weight_gram, stone_weight_gram, net_weight_gram,
            rate_per_gram, gold_value, making_charge, stone_value, item_total, qty
        ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
    ");
    $barcodeUpd = $pdo->prepare("
        UPDATE barcode_stock
           SET status = 'sold', sold_at = NOW()
         WHERE id = ? AND status = 'in_stock'
    ");
    $newStockCheck = $pdo->prepare("
        SELECT product_name, available_weight_gram, available_pcs
          FROM new_stock
         WHERE id = ? AND deleted_at IS NULL
    ");
    $newStockUpd = $pdo->prepare("
        UPDATE new_stock
           SET available_weight_gram = available_weight_gram - ?,
               available_pcs         = GREATEST(0, available_pcs - ?)
         WHERE id = ?
    ");

    foreach ($items as $it) {
        $source = $it['source_type'] ?? 'barcode';
        $itemStmt->execute([
            $sale_id, $source,
            $it['barcode_stock_id'] ?? null,
            $it['new_stock_id']     ?? null,
            $it['product_name']     ?? '',
            $it['category']         ?? null,
            $it['barcode']          ?? null,
            $it['karat']            ?? null,
            $it['purity_percent']   ?? null,
            (float)($it['gross_weight_gram'] ?? 0),
            (float)($it['stone_weight_gram'] ?? 0),
            (float)($it['net_weight_gram']   ?? 0),
            (float)($it['rate_per_gram']     ?? 0),
            (float)($it['gold_value']        ?? 0),
            (float)($it['making_charge']     ?? 0),
            (float)($it['stone_value']       ?? 0),
            (float)($it['item_total']        ?? 0),
            (int)  ($it['qty'] ?? 1)
        ]);

        if ($source === 'barcode' && !empty($it['barcode_stock_id'])) {
            $barcodeUpd->execute([(int)$it['barcode_stock_id']]);
            if ($barcodeUpd->rowCount() === 0) {
                throw new Exception("Barcode #{$it['barcode_stock_id']} ইতিমধ্যে sold বা পাওয়া যায়নি");
            }
        } elseif ($source === 'new_stock' && !empty($it['new_stock_id'])) {
            $req_weight = (float)($it['gross_weight_gram'] ?? 0);
            $req_qty    = (int)($it['qty'] ?? 1);

            $newStockCheck->execute([(int)$it['new_stock_id']]);
            $ns = $newStockCheck->fetch(PDO::FETCH_ASSOC);
            if (!$ns) {
                throw new Exception("New stock #{$it['new_stock_id']} পাওয়া যায়নি");
            }
            if ((float)$ns['available_weight_gram'] < $req_weight - 0.001) {
                throw new Exception(
                    "{$ns['product_name']}: পর্যাপ্ত weight নেই " .
                    "(available {$ns['available_weight_gram']}g, requested {$req_weight}g)"
                );
            }
            $newStockUpd->execute([$req_weight, $req_qty, (int)$it['new_stock_id']]);
        }
    }

    // ============================================================
    // 6) Exchanges (পুরনো সোনা)
    // ============================================================
    if (!empty($exchanges)) {
        $exStmt = $pdo->prepare("
            INSERT INTO sale_exchanges (
                sale_id, item_description, karat, purity_percent,
                gross_weight_gram, pure_gold_gram, rate_per_gram, exchange_value,
                goes_to_old_gold_stock
            ) VALUES (?,?,?,?,?,?,?,?,?)
        ");
        foreach ($exchanges as $ex) {
            $exStmt->execute([
                $sale_id,
                $ex['item_description'] ?? '',
                $ex['karat']            ?? '22K',
                (float)($ex['purity_percent']    ?? 0),
                (float)($ex['gross_weight_gram'] ?? 0),
                (float)($ex['pure_gold_gram']    ?? 0),
                (float)($ex['rate_per_gram']     ?? 0),
                (float)($ex['exchange_value']    ?? 0),
                (int)  ($ex['goes_to_old_gold_stock'] ?? 1)
            ]);
        }
    }

    // ============================================================
    // 7) Payments + cash_transactions (helper দিয়ে)
    // ============================================================
    $payStmt = $pdo->prepare("
        INSERT INTO sale_payments (
            sale_id, cash_account_id, amount, reference_no, cash_transaction_id
        ) VALUES (?,?,?,?,?)
    ");

    $catS = $pdo->prepare("SELECT id FROM cash_categories WHERE category_code = 'SALE_RECEIPT' LIMIT 1");
    $catS->execute();
    $saleCatId = (int)$catS->fetchColumn();

    if ($saleCatId <= 0) {
        $dbName = (string)$pdo->query("SELECT DATABASE()")->fetchColumn();
        throw new Exception("SALE_RECEIPT category পাওয়া যায়নি (connected DB: {$dbName})");
    }

    $txnDate          = date('Y-m-d', strtotime($sale_date));
    $recalcAccountIds = [];

    foreach ($payments as $p) {
        $amt           = (float)($p['amount']          ?? 0);
        $cashAccountId = (int)  ($p['cash_account_id'] ?? 0);
        if ($amt <= 0 || $cashAccountId <= 0) continue;

        $cash_txn_id = gs_insert_cash_transaction($pdo, [
            'category_id'      => $saleCatId,
            'cash_account_id'  => $cashAccountId,
            'amount'           => $amt,
            'transaction_date' => $txnDate,
            'note'             => "Sale #{$invoice_no}",
            'reference_type'   => 'SALE',
            'reference_id'     => $sale_id,
            'party_id'         => $customer_id,
            'created_by'       => $user_id
        ]);

        $payStmt->execute([
            $sale_id,
            $cashAccountId,
            $amt,
            $p['reference_no'] ?? null,
            $cash_txn_id
        ]);

        $recalcAccountIds[] = $cashAccountId;
    }

    gs_recalc_cash_accounts($pdo, $recalcAccountIds);
    gs_sync_sale_payment_summary($pdo, $sale_id);

    $pdo->commit();

    echo json_encode([
        'ok'              => true,
        'sale_id'         => $sale_id,
        'invoice_no'      => $invoice_no,
        'grand_total'     => round($grand_total, 2),
        'items_subtotal'  => round($items_subtotal, 2),
        'vat_amount'      => round($vat_amount, 2),
        'exchange_value'  => round($exchange_value, 2),
        'paid_total'      => round($paid_total, 2),
        'due_amount'      => round($due_amount, 2),
        'payment_status'  => $payment_status,
        'customer_id'     => $customer_id,
        'party_auto_saved'=> $party_auto_saved,
        'message'         => "Sale #{$invoice_no} সফলভাবে সংরক্ষিত হয়েছে।"
            . ($party_auto_saved ? " গ্রাহক '{$customer_name}' parties-এ যোগ হয়েছে।" : '')
    ]);

} catch (Exception $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    http_response_code(500);
    echo json_encode([
        'ok'    => false,
        'error' => $e->getMessage()
    ]);
}
