<?php
require_once __DIR__ . '/../../includes/bootstrap.php';
require_login();

$pageTitle = 'Purchase Orders';

if (!function_exists('h')) {
    function h($value): string { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); }
}
if (!function_exists('money_fmt')) {
    function money_fmt($amount): string { return number_format((float)$amount, 2); }
}
if (!function_exists('po_flash')) {
    function po_flash(string $type, string $message): void {
        $_SESSION['purchase_orders_flash'][] = ['type' => $type, 'message' => $message];
    }
}
if (!function_exists('po_get_flash')) {
    function po_get_flash(): array {
        $items = $_SESSION['purchase_orders_flash'] ?? [];
        unset($_SESSION['purchase_orders_flash']);
        return $items;
    }
}
if (!function_exists('po_column_exists')) {
    function po_column_exists(PDO $pdo, string $tableName, string $columnName): bool {
        $stmt = $pdo->prepare("
            SELECT COUNT(*)
            FROM information_schema.columns
            WHERE table_schema = DATABASE()
              AND table_name = :table_name
              AND column_name = :column_name
        ");
        $stmt->execute([':table_name' => $tableName, ':column_name' => $columnName]);
        return (int)$stmt->fetchColumn() > 0;
    }
}
if (!function_exists('purchase_order_no')) {
    function purchase_order_no(PDO $pdo): string {
        $prefix = 'PO-' . date('ymd') . '-';
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM inventory_purchase_orders WHERE po_no LIKE :p");
        $stmt->execute([':p' => $prefix . '%']);
        return $prefix . str_pad((string)((int)$stmt->fetchColumn() + 1), 4, '0', STR_PAD_LEFT);
    }
}
if (!function_exists('po_grn_no')) {
    function po_grn_no(PDO $pdo): string {
        $prefix = 'GRN-' . date('ymd') . '-';
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM inventory_grns WHERE grn_no LIKE :p");
        $stmt->execute([':p' => $prefix . '%']);
        return $prefix . str_pad((string)((int)$stmt->fetchColumn() + 1), 4, '0', STR_PAD_LEFT);
    }
}
if (!function_exists('po_calc_line_amounts')) {
    /*
       $grossOverride: same approach as grn.php - when the LINE AMOUNT is
       entered straight off the supplier quote/invoice, use it as the exact
       gross instead of round(qty x unit price, 2). Fixes documents whose
       printed unit price is rounded to 2dp while the true price has more
       decimals, so qty x printed-price is a few cents off the document total.
    */
    function po_calc_line_amounts(float $qty, float $unitPriceInput, string $taxType, float $taxRate, string $priceTaxMode, ?float $grossOverride = null): array {
        $qty = max(0, $qty);
        $unitPriceInput = max(0, $unitPriceInput);
        $grossInput = $grossOverride !== null
            ? round(max(0, $grossOverride), 2)
            : round($qty * $unitPriceInput, 2);
        $taxType = $taxType === 'Fixed' ? 'Fixed' : 'Percentage';
        $priceTaxMode = $priceTaxMode === 'inclusive' ? 'inclusive' : 'exclusive';

        if ($taxRate <= 0) {
            return [
                'net' => $grossInput,
                'tax' => 0.0,
                'total' => $grossInput,
                'stock_unit_cost' => $qty > 0 ? round($grossInput / $qty, 4) : 0.0,
            ];
        }

        if ($priceTaxMode === 'inclusive') {
            if ($taxType === 'Fixed') {
                $tax = round($taxRate * max(1, $qty), 2);
                $net = max(0, round($grossInput - $tax, 2));
                $total = $grossInput;
            } else {
                $tax = round($grossInput * ($taxRate / (100 + $taxRate)), 2);
                $net = round($grossInput - $tax, 2);
                $total = $grossInput;
            }
        } else {
            $net = $grossInput;
            $tax = $taxType === 'Fixed' ? round($taxRate * max(1, $qty), 2) : round($net * ($taxRate / 100), 2);
            $total = round($net + $tax, 2);
        }

        return [
            'net' => $net,
            'tax' => $tax,
            'total' => $total,
            'stock_unit_cost' => $qty > 0 ? round($net / $qty, 4) : 0.0,
        ];
    }
}
if (!function_exists('po_line_tax_amount')) {
    function po_line_tax_amount(float $net, float $qty, string $taxType, float $taxRate): float {
        if ($taxRate <= 0) return 0.0;
        return $taxType === 'Fixed' ? round($taxRate * max(1, $qty), 2) : round($net * ($taxRate / 100), 2);
    }
}

if (!function_exists('po_recalc_avg_cost')) {
    function po_recalc_avg_cost(PDO $pdo, int $itemId): void {
        $stmt = $pdo->prepare("
            SELECT COALESCE(SUM(qty_in),0) qty, COALESCE(SUM(qty_in * unit_cost),0) cost
            FROM stock_movements
            WHERE item_id = :item_id
              AND qty_in > 0
              AND movement_type IN ('OPENING','GRN','TRANSFER_IN','ADJUSTMENT_IN','RETURN')
        ");
        $stmt->execute([':item_id' => $itemId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $qty = (float)($row['qty'] ?? 0);
        $cost = (float)($row['cost'] ?? 0);

        if ($qty > 0) {
            $avg = $cost / $qty;
            $stmt = $pdo->prepare("
                UPDATE inventory_items
                SET avg_cost = :avg_cost,
                    cost_price = CASE WHEN cost_price = 0 THEN :avg_cost_for_cost_price ELSE cost_price END
                WHERE id = :id
            ");
            $stmt->execute([
                ':avg_cost' => $avg,
                ':avg_cost_for_cost_price' => $avg,
                ':id' => $itemId
            ]);
        }
    }
}

$errors = [];

try {
    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_suppliers (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        supplier_code VARCHAR(60) NULL,
        supplier_name VARCHAR(180) NOT NULL,
        contact_person VARCHAR(150) NULL,
        phone VARCHAR(80) NULL,
        email VARCHAR(150) NULL,
        address TEXT NULL,
        payment_terms VARCHAR(120) NULL,
        tax_number VARCHAR(120) NULL,
        notes TEXT NULL,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_inventory_supplier_name (supplier_name)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS store_locations (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        location_code VARCHAR(50) NULL,
        location_name VARCHAR(150) NOT NULL,
        location_type ENUM('main_store','bar','restaurant','curio','kitchen','housekeeping','maintenance','other') NOT NULL DEFAULT 'main_store',
        is_pos_location TINYINT(1) NOT NULL DEFAULT 0,
        allow_room_charge TINYINT(1) NOT NULL DEFAULT 1,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        notes TEXT NULL,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_store_location_code (location_code)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_item_categories (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        category_name VARCHAR(120) NOT NULL,
        category_type ENUM('stock','food','bar','curio','consumable','service','other') NOT NULL DEFAULT 'stock',
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_inventory_category_name (category_name)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_units (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        unit_code VARCHAR(30) NOT NULL,
        unit_name VARCHAR(80) NOT NULL,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY uq_inventory_unit_code (unit_code)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS taxes (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        code VARCHAR(32) NOT NULL,
        type ENUM('Percentage','Fixed','','') NOT NULL,
        rate DECIMAL(10,2) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_items (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        item_code VARCHAR(60) NULL,
        item_name VARCHAR(180) NOT NULL,
        category_id INT UNSIGNED NULL,
        unit_id INT UNSIGNED NULL,
        item_type ENUM('stock','food','bar','curio','consumable','service','recipe','other') NOT NULL DEFAULT 'stock',
        barcode VARCHAR(100) NULL,
        description TEXT NULL,
        cost_price DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        avg_cost DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        selling_price DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        tax_rate DECIMAL(7,4) NOT NULL DEFAULT 0.0000,
        reorder_level DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        reorder_qty DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        is_stock_item TINYINT(1) NOT NULL DEFAULT 1,
        is_pos_item TINYINT(1) NOT NULL DEFAULT 0,
        allow_room_charge TINYINT(1) NOT NULL DEFAULT 1,
        track_expiry TINYINT(1) NOT NULL DEFAULT 0,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_inventory_item_code (item_code)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS stock_movements (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        item_id INT UNSIGNED NOT NULL,
        store_id INT UNSIGNED NOT NULL,
        movement_type ENUM('OPENING','GRN','ISSUE','SALE','TRANSFER_IN','TRANSFER_OUT','ADJUSTMENT_IN','ADJUSTMENT_OUT','WASTAGE','RETURN') NOT NULL,
        qty_in DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        qty_out DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        unit_cost DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        total_cost DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        reference_type VARCHAR(60) NULL,
        reference_id BIGINT UNSIGNED NULL,
        notes TEXT NULL,
        movement_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_stock_reference (reference_type, reference_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_purchase_orders (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        po_no VARCHAR(60) NOT NULL,
        supplier_id INT UNSIGNED NOT NULL,
        supplier_name VARCHAR(180) NULL,
        store_id INT UNSIGNED NOT NULL,
        po_date DATE NOT NULL,
        expected_date DATE NULL,
        status ENUM('draft','approved','part_received','received','cancelled','void') NOT NULL DEFAULT 'draft',
        subtotal DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        tax_amount DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        total_amount DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        notes TEXT NULL,
        created_by INT UNSIGNED NULL,
        approved_by INT UNSIGNED NULL,
        approved_at DATETIME NULL,
        cancelled_reason TEXT NULL,
        cancelled_at DATETIME NULL,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_po_no (po_no),
        INDEX idx_po_supplier (supplier_id),
        INDEX idx_po_store (store_id),
        INDEX idx_po_status (status),
        INDEX idx_po_date (po_date)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_purchase_order_lines (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        po_id BIGINT UNSIGNED NOT NULL,
        item_id INT UNSIGNED NOT NULL,
        tax_id INT UNSIGNED NULL,
        tax_name VARCHAR(255) NULL,
        tax_type VARCHAR(30) NULL,
        price_tax_mode ENUM('exclusive','inclusive') NOT NULL DEFAULT 'exclusive',
        unit_price_entered DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        qty_ordered DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        qty_received DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        unit_cost DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        tax_rate DECIMAL(7,4) NOT NULL DEFAULT 0.0000,
        line_tax DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        line_total DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        notes TEXT NULL,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_po_line_po (po_id),
        INDEX idx_po_line_item (item_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_grns (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        grn_no VARCHAR(60) NOT NULL,
        supplier_id INT UNSIGNED NULL,
        supplier_name VARCHAR(180) NULL,
        store_id INT UNSIGNED NOT NULL,
        po_id BIGINT UNSIGNED NULL,
        invoice_no VARCHAR(100) NULL,
        grn_date DATE NOT NULL,
        subtotal DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        tax_amount DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        total_amount DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        status ENUM('posted','void') NOT NULL DEFAULT 'posted',
        notes TEXT NULL,
        created_by INT UNSIGNED NULL,
        void_reason TEXT NULL,
        voided_at DATETIME NULL,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_grn_no (grn_no),
        INDEX idx_grn_supplier (supplier_id),
        INDEX idx_grn_po (po_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $colCheck = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name='inventory_grns' AND column_name=:col");
    $colCheck->execute([':col' => 'po_id']);
    if ((int)$colCheck->fetchColumn() === 0) {
        $pdo->exec("ALTER TABLE inventory_grns ADD COLUMN po_id BIGINT UNSIGNED NULL AFTER store_id");
    }

    $poLineTaxCheck = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name='inventory_purchase_order_lines' AND column_name='tax_id'");
    $poLineTaxCheck->execute();
    if ((int)$poLineTaxCheck->fetchColumn() === 0) {
        $pdo->exec("ALTER TABLE inventory_purchase_order_lines ADD COLUMN tax_id INT UNSIGNED NULL AFTER item_id");
    }

    foreach ([
        'tax_name' => "ALTER TABLE inventory_purchase_order_lines ADD COLUMN tax_name VARCHAR(255) NULL AFTER tax_id",
        'tax_type' => "ALTER TABLE inventory_purchase_order_lines ADD COLUMN tax_type VARCHAR(30) NULL AFTER tax_name",
        'price_tax_mode' => "ALTER TABLE inventory_purchase_order_lines ADD COLUMN price_tax_mode ENUM('exclusive','inclusive') NOT NULL DEFAULT 'exclusive' AFTER tax_type",
        'unit_price_entered' => "ALTER TABLE inventory_purchase_order_lines ADD COLUMN unit_price_entered DECIMAL(14,4) NOT NULL DEFAULT 0.0000 AFTER price_tax_mode"
    ] as $col => $sql) {
        if (!po_column_exists($pdo, 'inventory_purchase_order_lines', $col)) {
            $pdo->exec($sql);
        }
    }

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_grn_lines (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        grn_id BIGINT UNSIGNED NOT NULL,
        item_id INT UNSIGNED NOT NULL,
        store_id INT UNSIGNED NOT NULL,
        tax_id INT UNSIGNED NULL,
        tax_name VARCHAR(255) NULL,
        tax_type VARCHAR(30) NULL,
        price_tax_mode ENUM('exclusive','inclusive') NOT NULL DEFAULT 'exclusive',
        unit_price_entered DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        qty DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        unit_cost DECIMAL(14,4) NOT NULL DEFAULT 0.0000,
        tax_rate DECIMAL(7,4) NOT NULL DEFAULT 0.0000,
        line_tax DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        line_total DECIMAL(14,2) NOT NULL DEFAULT 0.00,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_grn_line_grn (grn_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    foreach ([
        'store_id' => "ALTER TABLE inventory_grn_lines ADD COLUMN store_id INT UNSIGNED NULL AFTER item_id",
        'tax_id' => "ALTER TABLE inventory_grn_lines ADD COLUMN tax_id INT UNSIGNED NULL AFTER store_id",
        'tax_name' => "ALTER TABLE inventory_grn_lines ADD COLUMN tax_name VARCHAR(255) NULL AFTER tax_id",
        'tax_type' => "ALTER TABLE inventory_grn_lines ADD COLUMN tax_type VARCHAR(30) NULL AFTER tax_name",
        'price_tax_mode' => "ALTER TABLE inventory_grn_lines ADD COLUMN price_tax_mode ENUM('exclusive','inclusive') NOT NULL DEFAULT 'exclusive' AFTER tax_type",
        'unit_price_entered' => "ALTER TABLE inventory_grn_lines ADD COLUMN unit_price_entered DECIMAL(14,4) NOT NULL DEFAULT 0.0000 AFTER price_tax_mode"
    ] as $col => $sql) {
        if (!po_column_exists($pdo, 'inventory_grn_lines', $col)) {
            $pdo->exec($sql);
        }
    }

} catch (Throwable $e) {
    $errors[] = 'Could not prepare purchase order tables: ' . $e->getMessage();
}

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    try {
        if (function_exists('verify_csrf')) verify_csrf();

        $action = (string)($_POST['action'] ?? '');

        if ($action === 'quick_add_item') {
            header('Content-Type: application/json; charset=utf-8');
            $itemName = trim((string)($_POST['item_name'] ?? ''));
            $itemCode = trim((string)($_POST['item_code'] ?? ''));
            $categoryId = (int)($_POST['category_id'] ?? 0);
            $unitId = (int)($_POST['unit_id'] ?? 0);
            $costPrice = max(0, (float)($_POST['cost_price'] ?? 0));
            $taxRate = max(0, (float)($_POST['tax_rate'] ?? 0));
            if ($itemName === '') throw new RuntimeException('Item name is required.');
            if ($itemCode !== '') {
                $chk = $pdo->prepare("SELECT COUNT(*) FROM inventory_items WHERE item_code = :code");
                $chk->execute([':code' => $itemCode]);
                if ((int)$chk->fetchColumn() > 0) throw new RuntimeException('That item code already exists.');
            }
            $stmt = $pdo->prepare("INSERT INTO inventory_items
                (item_code,item_name,category_id,unit_id,item_type,cost_price,avg_cost,tax_rate,is_stock_item,is_active)
                VALUES (:code,:name,:category_id,:unit_id,'stock',:cost_price,:avg_cost,:tax_rate,1,1)");
            $stmt->execute([
                ':code' => $itemCode !== '' ? $itemCode : null,
                ':name' => $itemName,
                ':category_id' => $categoryId > 0 ? $categoryId : null,
                ':unit_id' => $unitId > 0 ? $unitId : null,
                ':cost_price' => $costPrice,
                ':avg_cost' => $costPrice,
                ':tax_rate' => $taxRate,
            ]);
            echo json_encode(['ok'=>true,'item'=>['id'=>(int)$pdo->lastInsertId(),'name'=>$itemName,'code'=>$itemCode,'cost'=>$costPrice,'tax'=>$taxRate]]);
            exit;
        }

        if ($action === 'create_po') {
            $poIdToUpdate = (int)($_POST['po_id'] ?? 0);
            $submitMode = (string)($_POST['submit_mode'] ?? 'draft');
            $supplierId = (int)($_POST['supplier_id'] ?? 0);
            $storeId = (int)($_POST['store_id'] ?? 0);
            $poDate = trim((string)($_POST['po_date'] ?? date('Y-m-d')));
            $expectedDate = trim((string)($_POST['expected_date'] ?? ''));
            $notes = trim((string)($_POST['notes'] ?? ''));

            $itemIds = $_POST['item_id'] ?? [];
            $qtys = $_POST['qty_ordered'] ?? [];
            $unitCosts = $_POST['unit_cost'] ?? [];
            $lineAmounts = $_POST['line_amount'] ?? [];
            $taxIds = $_POST['tax_id'] ?? [];
            $priceTaxModes = $_POST['price_tax_mode'] ?? [];

            if ($supplierId <= 0) throw new RuntimeException('Please select supplier.');
            if ($storeId <= 0) throw new RuntimeException('Please select receiving store.');
            if (strtotime($poDate) === false) $poDate = date('Y-m-d');
            if ($expectedDate !== '' && strtotime($expectedDate) === false) $expectedDate = null;

            $stmt = $pdo->prepare("SELECT supplier_name FROM inventory_suppliers WHERE id = :id LIMIT 1");
            $stmt->execute([':id' => $supplierId]);
            $supplierName = (string)($stmt->fetchColumn() ?: '');
            if ($supplierName === '') throw new RuntimeException('Supplier not found.');

            $taxMap = [];
            $taxRows = $pdo->query("SELECT id, name, code, type, rate FROM taxes ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
            foreach ($taxRows as $taxRow) {
                $taxMap[(int)$taxRow['id']] = $taxRow;
            }

            $lines = [];
            $subtotal = 0.0;
            $taxAmount = 0.0;

            foreach ($itemIds as $idx => $itemIdRaw) {
                $itemId = (int)$itemIdRaw;
                $qtyRaw = trim((string)($qtys[$idx] ?? '0'));
                $qty = (float)$qtyRaw;
                $unitPriceInput = (float)($unitCosts[$idx] ?? 0);

                /* Entered line amount (optional). Empty = calculate from unit
                   price as before; a value = the amount is authoritative. */
                $lineAmountRaw = trim(str_replace(',', '', (string)($lineAmounts[$idx] ?? '')));
                $lineAmountInput = ($lineAmountRaw !== '' && is_numeric($lineAmountRaw)) ? (float)$lineAmountRaw : null;

                $priceTaxModeRaw = strtolower(trim((string)($priceTaxModes[$idx] ?? 'exclusive')));
                $priceTaxMode = $priceTaxModeRaw === 'inclusive' ? 'inclusive' : 'exclusive';
                $taxId = (int)($taxIds[$idx] ?? 0);
                $taxRate = 0.0;
                $taxType = 'Percentage';
                $taxName = null;
                if ($taxId > 0) {
                    if (!isset($taxMap[$taxId])) throw new RuntimeException('Invalid tax line selected.');
                    $taxRate = (float)$taxMap[$taxId]['rate'];
                    $taxType = ((string)$taxMap[$taxId]['type']) === 'Fixed' ? 'Fixed' : 'Percentage';
                    $taxName = (string)($taxMap[$taxId]['name'] ?? '');
                }

                if ($itemId <= 0 && $qty <= 0) continue;
                if ($itemId <= 0) throw new RuntimeException('One PO line is missing an item.');
                if ($qty <= 0) throw new RuntimeException('Quantity must be greater than zero.');
                /* Allow measured quantities such as 30.3 kg, 12.75 litres, etc. */
                $qty = round($qty, 4);
                if ($unitPriceInput < 0) throw new RuntimeException('Unit cost cannot be negative.');
                if ($lineAmountInput !== null && $lineAmountInput < 0) throw new RuntimeException('Line amount cannot be negative.');

                $stmt = $pdo->prepare("SELECT * FROM inventory_items WHERE id = :id LIMIT 1");
                $stmt->execute([':id' => $itemId]);
                $item = $stmt->fetch(PDO::FETCH_ASSOC);
                if (!$item) throw new RuntimeException('Invalid inventory item selected.');
                if ((int)$item['is_stock_item'] !== 1) throw new RuntimeException($item['item_name'] . ' is not a stock item.');

                $amounts = po_calc_line_amounts((float)$qty, $unitPriceInput, $taxType, $taxRate, $priceTaxMode, $lineAmountInput);
                $net = round((float)$amounts['net'], 2);
                $tax = round((float)$amounts['tax'], 2);
                $lineTotal = round((float)$amounts['total'], 2);
                $stockUnitCost = round((float)$amounts['stock_unit_cost'], 4);

                /* When the amount drove the line, the true unit price is the
                   derived one - store it so the PO prints real numbers. */
                $unitPriceStored = $unitPriceInput;
                if ($lineAmountInput !== null && $qty > 0 && $unitPriceInput <= 0) {
                    $unitPriceStored = round($lineAmountInput / $qty, 4);
                }

                $subtotal += $net;
                $taxAmount += $tax;

                $lines[] = [
                    'item_id' => $itemId,
                    'qty' => $qty,
                    'unit_price_entered' => $unitPriceStored,
                    'unit_cost' => $stockUnitCost,
                    'tax_id' => $taxId > 0 ? $taxId : null,
                    'tax_name' => $taxName !== '' ? $taxName : null,
                    'tax_type' => $taxType,
                    'price_tax_mode' => $priceTaxMode,
                    'tax_rate' => $taxRate,
                    'line_tax' => $tax,
                    'line_total' => $lineTotal,
                ];
            }

            if (!$lines) throw new RuntimeException('Please add at least one PO line.');

            $pdo->beginTransaction();

            $targetStatus = $submitMode === 'approve' ? 'approved' : 'draft';
            if ($poIdToUpdate > 0) {
                $check = $pdo->prepare("SELECT po_no,status FROM inventory_purchase_orders WHERE id=:id FOR UPDATE");
                $check->execute([':id'=>$poIdToUpdate]);
                $existingPo = $check->fetch(PDO::FETCH_ASSOC);
                if (!$existingPo) throw new RuntimeException('Draft purchase order not found.');
                if ($existingPo['status'] !== 'draft') throw new RuntimeException('Only draft purchase orders can be edited.');
                $poNo = (string)$existingPo['po_no'];
                $stmt = $pdo->prepare("UPDATE inventory_purchase_orders SET
                    supplier_id=:supplier_id,supplier_name=:supplier_name,store_id=:store_id,
                    po_date=:po_date,expected_date=:expected_date,status=:status,
                    subtotal=:subtotal,tax_amount=:tax_amount,total_amount=:total_amount,notes=:notes,
                    approved_by=:approved_by,approved_at=:approved_at
                    WHERE id=:id");
                $stmt->execute([
                    ':supplier_id'=>$supplierId, ':supplier_name'=>$supplierName, ':store_id'=>$storeId,
                    ':po_date'=>date('Y-m-d',strtotime($poDate)), ':expected_date'=>$expectedDate ? date('Y-m-d',strtotime($expectedDate)) : null,
                    ':status'=>$targetStatus, ':subtotal'=>$subtotal, ':tax_amount'=>$taxAmount, ':total_amount'=>$subtotal+$taxAmount,
                    ':notes'=>$notes ?: null, ':approved_by'=>$targetStatus==='approved' ? ($_SESSION['user_id'] ?? null) : null,
                    ':approved_at'=>$targetStatus==='approved' ? date('Y-m-d H:i:s') : null, ':id'=>$poIdToUpdate
                ]);
                $pdo->prepare("DELETE FROM inventory_purchase_order_lines WHERE po_id=:po_id")->execute([':po_id'=>$poIdToUpdate]);
                $poId = $poIdToUpdate;
            } else {
                $poNo = purchase_order_no($pdo);
                $stmt = $pdo->prepare("INSERT INTO inventory_purchase_orders
                    (po_no,supplier_id,supplier_name,store_id,po_date,expected_date,status,subtotal,tax_amount,total_amount,notes,created_by,approved_by,approved_at)
                    VALUES (:po_no,:supplier_id,:supplier_name,:store_id,:po_date,:expected_date,:status,:subtotal,:tax_amount,:total_amount,:notes,:created_by,:approved_by,:approved_at)");
                $stmt->execute([
                    ':po_no'=>$poNo, ':supplier_id'=>$supplierId, ':supplier_name'=>$supplierName, ':store_id'=>$storeId,
                    ':po_date'=>date('Y-m-d',strtotime($poDate)), ':expected_date'=>$expectedDate ? date('Y-m-d',strtotime($expectedDate)) : null,
                    ':status'=>$targetStatus, ':subtotal'=>$subtotal, ':tax_amount'=>$taxAmount, ':total_amount'=>$subtotal+$taxAmount,
                    ':notes'=>$notes ?: null, ':created_by'=>$_SESSION['user_id'] ?? null,
                    ':approved_by'=>$targetStatus==='approved' ? ($_SESSION['user_id'] ?? null) : null,
                    ':approved_at'=>$targetStatus==='approved' ? date('Y-m-d H:i:s') : null,
                ]);
                $poId = (int)$pdo->lastInsertId();
            }

            $stmt = $pdo->prepare("
                INSERT INTO inventory_purchase_order_lines
                (po_id, item_id, tax_id, tax_name, tax_type, price_tax_mode, unit_price_entered, qty_ordered, qty_received, unit_cost, tax_rate, line_tax, line_total)
                VALUES
                (:po_id, :item_id, :tax_id, :tax_name, :tax_type, :price_tax_mode, :unit_price_entered, :qty_ordered, 0, :unit_cost, :tax_rate, :line_tax, :line_total)
            ");
            foreach ($lines as $line) {
                $stmt->execute([
                    ':po_id' => $poId,
                    ':item_id' => $line['item_id'],
                    ':tax_id' => $line['tax_id'],
                    ':tax_name' => $line['tax_name'],
                    ':tax_type' => $line['tax_type'],
                    ':price_tax_mode' => $line['price_tax_mode'],
                    ':unit_price_entered' => $line['unit_price_entered'],
                    ':qty_ordered' => $line['qty'],
                    ':unit_cost' => $line['unit_cost'],
                    ':tax_rate' => $line['tax_rate'],
                    ':line_tax' => $line['line_tax'],
                    ':line_total' => $line['line_total'],
                ]);
            }

            $pdo->commit();

            po_flash('success', ($targetStatus === 'approved' ? 'Purchase order saved and approved: ' : 'Draft purchase order saved: ') . $poNo);
            header('Location: purchase_orders.php?view_id=' . $poId);
            exit;
        }

        if ($action === 'approve_po') {
            $poId = (int)($_POST['po_id'] ?? 0);
            if ($poId <= 0) throw new RuntimeException('Invalid PO selected.');

            $stmt = $pdo->prepare("
                UPDATE inventory_purchase_orders
                SET status = 'approved',
                    approved_by = :approved_by,
                    approved_at = NOW()
                WHERE id = :id
                  AND status = 'draft'
            ");
            $stmt->execute([':approved_by' => $_SESSION['user_id'] ?? null, ':id' => $poId]);

            po_flash('success', 'Purchase order approved.');
            header('Location: purchase_orders.php?view_id=' . $poId);
            exit;
        }

        if ($action === 'cancel_po') {
            $poId = (int)($_POST['po_id'] ?? 0);
            $reason = trim((string)($_POST['cancelled_reason'] ?? ''));
            if ($poId <= 0) throw new RuntimeException('Invalid PO selected.');
            if ($reason === '') throw new RuntimeException('Cancellation reason is required.');

            $stmt = $pdo->prepare("
                UPDATE inventory_purchase_orders
                SET status = 'cancelled',
                    cancelled_reason = :reason,
                    cancelled_at = NOW()
                WHERE id = :id
                  AND status IN ('draft','approved')
            ");
            $stmt->execute([':reason' => $reason, ':id' => $poId]);

            po_flash('success', 'Purchase order cancelled.');
            header('Location: purchase_orders.php?view_id=' . $poId);
            exit;
        }

        if ($action === 'receive_po') {
            $poId = (int)($_POST['po_id'] ?? 0);
            $invoiceNo = trim((string)($_POST['invoice_no'] ?? ''));
            $grnDate = trim((string)($_POST['grn_date'] ?? date('Y-m-d')));
            $notes = trim((string)($_POST['receive_notes'] ?? ''));

            $receiveQty = $_POST['receive_qty'] ?? [];
            $receivePrice = $_POST['receive_price'] ?? [];
            $receiveAmount = $_POST['receive_amount'] ?? [];
            $receiveStore = $_POST['receive_store_id'] ?? [];

            if ($poId <= 0) throw new RuntimeException('Invalid PO selected.');
            if (strtotime($grnDate) === false) $grnDate = date('Y-m-d');

            $stmt = $pdo->prepare("SELECT * FROM inventory_purchase_orders WHERE id = :id LIMIT 1");
            $stmt->execute([':id' => $poId]);
            $po = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$po) throw new RuntimeException('Purchase order not found.');
            if (!in_array($po['status'], ['approved','part_received'], true)) throw new RuntimeException('Only approved or partially received POs can be received.');

            $stmt = $pdo->prepare("
                SELECT pol.*, ii.item_name, COALESCE(pol.tax_type, t.type, 'Percentage') AS tax_type
                FROM inventory_purchase_order_lines pol
                INNER JOIN inventory_items ii ON ii.id = pol.item_id
                LEFT JOIN taxes t ON t.id = pol.tax_id
                WHERE pol.po_id = :po_id
                ORDER BY pol.id ASC
            ");
            $stmt->execute([':po_id' => $poId]);
            $poLines = $stmt->fetchAll(PDO::FETCH_ASSOC);

            /*
             * A PO has a default receiving store, but each received line may
             * override it. Only active storage areas may be selected.
             */
            $activeStoreMap = [];
            $storeStmt = $pdo->query("
                SELECT id, location_name
                FROM store_locations
                WHERE is_active = 1
                ORDER BY location_name ASC
            ");
            foreach ($storeStmt->fetchAll(PDO::FETCH_ASSOC) as $storeRow) {
                $activeStoreMap[(int)$storeRow['id']] = (string)$storeRow['location_name'];
            }

            $linesToReceive = [];
            $subtotal = 0.0;
            $taxAmount = 0.0;

            foreach ($poLines as $line) {
                $lineId = (int)$line['id'];
                $qtyRaw = trim((string)($receiveQty[$lineId] ?? '0'));
                $qty = (float)$qtyRaw;
                $remaining = max(0, (float)$line['qty_ordered'] - (float)$line['qty_received']);

                /*
                 * Default to the PO receiving store. A selected line store
                 * overrides it for this GRN line and its stock movement.
                 */
                $lineStoreId = (int)($receiveStore[$lineId] ?? $po['store_id']);
                if ($lineStoreId <= 0) {
                    $lineStoreId = (int)$po['store_id'];
                }

                if ($qty <= 0) continue;

                if (!isset($activeStoreMap[$lineStoreId])) {
                    throw new RuntimeException(
                        'Please select a valid storage area for ' . $line['item_name'] . '.'
                    );
                }
                /* Allow decimal quantities when receiving stock. */
                $qty = round($qty, 4);
                if ($qty > $remaining) throw new RuntimeException('Receive qty for ' . $line['item_name'] . ' exceeds remaining qty.');

                $taxType = ((string)($line['tax_type'] ?? 'Percentage')) === 'Fixed' ? 'Fixed' : 'Percentage';
                $priceTaxMode = ((string)($line['price_tax_mode'] ?? 'exclusive')) === 'inclusive' ? 'inclusive' : 'exclusive';

                /*
                   ACTUAL PRICE AT RECEIVING: the supplier's delivered price
                   can differ from what was on the PO. If an actual unit
                   price was entered for this line, it overrides the PO price
                   for the GRN valuation and stock movement cost; if an
                   actual line AMOUNT was entered (straight off the delivery
                   invoice), it is authoritative for the line - exactly the
                   grn.php behaviour - and the unit price derives from it.
                   Both left blank = PO price, unchanged behaviour.
                */
                $poUnitPrice = (float)(($line['unit_price_entered'] ?? 0) ?: ($line['unit_cost'] ?? 0));

                $actualPriceRaw = trim(str_replace(',', '', (string)($receivePrice[$lineId] ?? '')));
                $actualPrice = ($actualPriceRaw !== '' && is_numeric($actualPriceRaw)) ? (float)$actualPriceRaw : null;
                if ($actualPrice !== null && $actualPrice < 0) throw new RuntimeException('Actual unit price for ' . $line['item_name'] . ' cannot be negative.');

                $actualAmountRaw = trim(str_replace(',', '', (string)($receiveAmount[$lineId] ?? '')));
                $actualAmount = ($actualAmountRaw !== '' && is_numeric($actualAmountRaw)) ? (float)$actualAmountRaw : null;
                if ($actualAmount !== null && $actualAmount < 0) throw new RuntimeException('Actual amount for ' . $line['item_name'] . ' cannot be negative.');

                $unitPriceInput = $actualPrice !== null ? $actualPrice : $poUnitPrice;

                $amounts = po_calc_line_amounts((float)$qty, $unitPriceInput, $taxType, (float)$line['tax_rate'], $priceTaxMode, $actualAmount);
                $net = round((float)$amounts['net'], 2);
                $tax = round((float)$amounts['tax'], 2);
                $total = round((float)$amounts['total'], 2);
                $stockUnitCost = round((float)$amounts['stock_unit_cost'], 4);

                /* Record the price that actually applied on the GRN line. */
                $unitPriceStored = $unitPriceInput;
                if ($actualAmount !== null && $qty > 0 && $unitPriceInput <= 0) {
                    $unitPriceStored = round($actualAmount / $qty, 4);
                }

                $subtotal += $net;
                $taxAmount += $tax;

                $linesToReceive[] = [
                    'line_id' => $lineId,
                    'item_id' => (int)$line['item_id'],
                    'store_id' => $lineStoreId,
                    'store_name' => $activeStoreMap[$lineStoreId],
                    'tax_id' => !empty($line['tax_id']) ? (int)$line['tax_id'] : null,
                    'tax_name' => $line['tax_name'] ?? null,
                    'tax_type' => $taxType,
                    'price_tax_mode' => $priceTaxMode,
                    'unit_price_entered' => $unitPriceStored,
                    'qty' => $qty,
                    'unit_cost' => $stockUnitCost,
                    'tax_rate' => (float)$line['tax_rate'],
                    'line_tax' => $tax,
                    'line_total' => $total,
                ];
            }

            if (!$linesToReceive) throw new RuntimeException('Enter at least one quantity to receive.');

            $pdo->beginTransaction();

            $grnNo = po_grn_no($pdo);
            $stmt = $pdo->prepare("
                INSERT INTO inventory_grns
                (grn_no, supplier_id, supplier_name, store_id, po_id, invoice_no, grn_date, subtotal, tax_amount, total_amount, status, notes, created_by)
                VALUES
                (:grn_no, :supplier_id, :supplier_name, :store_id, :po_id, :invoice_no, :grn_date, :subtotal, :tax_amount, :total_amount, 'posted', :notes, :created_by)
            ");
            $stmt->execute([
                ':grn_no' => $grnNo,
                ':supplier_id' => (int)$po['supplier_id'],
                ':supplier_name' => $po['supplier_name'],
                ':store_id' => (int)$po['store_id'],
                ':po_id' => $poId,
                ':invoice_no' => $invoiceNo ?: null,
                ':grn_date' => date('Y-m-d', strtotime($grnDate)),
                ':subtotal' => $subtotal,
                ':tax_amount' => $taxAmount,
                ':total_amount' => $subtotal + $taxAmount,
                ':notes' => $notes ?: ('Received from PO ' . $po['po_no']),
                ':created_by' => $_SESSION['user_id'] ?? null,
            ]);
            $grnId = (int)$pdo->lastInsertId();

            $grnLineStmt = $pdo->prepare("
                INSERT INTO inventory_grn_lines
                (grn_id, item_id, store_id, tax_id, tax_name, tax_type, price_tax_mode, unit_price_entered, qty, unit_cost, tax_rate, line_tax, line_total)
                VALUES
                (:grn_id, :item_id, :store_id, :tax_id, :tax_name, :tax_type, :price_tax_mode, :unit_price_entered, :qty, :unit_cost, :tax_rate, :line_tax, :line_total)
            ");
            $movementStmt = $pdo->prepare("
                INSERT INTO stock_movements
                (item_id, store_id, movement_type, qty_in, qty_out, unit_cost, total_cost, reference_type, reference_id, notes, movement_date)
                VALUES
                (:item_id, :store_id, 'GRN', :qty, 0, :unit_cost, :total_cost, 'GRN', :reference_id, :notes, :movement_date)
            ");
            $lineUpdateStmt = $pdo->prepare("
                UPDATE inventory_purchase_order_lines
                SET qty_received = qty_received + :qty
                WHERE id = :id
            ");

            foreach ($linesToReceive as $line) {
                $grnLineStmt->execute([
                    ':grn_id' => $grnId,
                    ':item_id' => $line['item_id'],
                    ':store_id' => $line['store_id'],
                    ':tax_id' => $line['tax_id'],
                    ':tax_name' => $line['tax_name'],
                    ':tax_type' => $line['tax_type'],
                    ':price_tax_mode' => $line['price_tax_mode'],
                    ':unit_price_entered' => $line['unit_price_entered'],
                    ':qty' => $line['qty'],
                    ':unit_cost' => $line['unit_cost'],
                    ':tax_rate' => $line['tax_rate'],
                    ':line_tax' => $line['line_tax'],
                    ':line_total' => $line['line_total'],
                ]);

                $movementStmt->execute([
                    ':item_id' => $line['item_id'],
                    ':store_id' => $line['store_id'],
                    ':qty' => $line['qty'],
                    ':unit_cost' => $line['unit_cost'],
                    ':total_cost' => round($line['qty'] * $line['unit_cost'], 4),
                    ':reference_id' => $grnId,
                    ':notes' => 'GRN ' . $grnNo
                        . ' from PO ' . $po['po_no']
                        . ' received into ' . $line['store_name'],
                    ':movement_date' => date('Y-m-d H:i:s', strtotime($grnDate . ' ' . date('H:i:s'))),
                ]);

                $lineUpdateStmt->execute([
                    ':qty' => $line['qty'],
                    ':id' => $line['line_id'],
                ]);

                po_recalc_avg_cost($pdo, $line['item_id']);
            }

            $stmt = $pdo->prepare("
                SELECT
                    SUM(qty_ordered) AS ordered,
                    SUM(qty_received) AS received
                FROM inventory_purchase_order_lines
                WHERE po_id = :po_id
            ");
            $stmt->execute([':po_id' => $poId]);
            $totals = $stmt->fetch(PDO::FETCH_ASSOC);

            $ordered = (float)($totals['ordered'] ?? 0);
            $received = (float)($totals['received'] ?? 0);
            $newStatus = ($received >= $ordered && $ordered > 0) ? 'received' : 'part_received';

            $stmt = $pdo->prepare("UPDATE inventory_purchase_orders SET status = :status WHERE id = :id");
            $stmt->execute([':status' => $newStatus, ':id' => $poId]);

            $pdo->commit();

            po_flash('success', 'PO received into GRN: ' . $grnNo);
            header('Location: purchase_orders.php?view_id=' . $poId);
            exit;
        }

    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        if (($action ?? '') === 'quick_add_item') {
            http_response_code(422); header('Content-Type: application/json; charset=utf-8');
            echo json_encode(['ok'=>false,'message'=>$e->getMessage()]); exit;
        }
        po_flash('danger', $e->getMessage());
        header('Location: purchase_orders.php' . (!empty($_POST['po_id']) ? '?view_id=' . (int)$_POST['po_id'] : ''));
        exit;
    }
}

$suppliers = [];
$stores = [];
$items = [];
$taxes = [];
$itemCategories = [];
$units = [];

try {
    $suppliers = $pdo->query("SELECT * FROM inventory_suppliers WHERE is_active=1 ORDER BY supplier_name ASC")->fetchAll(PDO::FETCH_ASSOC);
    $stores = $pdo->query("SELECT * FROM store_locations WHERE is_active=1 ORDER BY location_name ASC")->fetchAll(PDO::FETCH_ASSOC);
    $taxes = $pdo->query("SELECT * FROM taxes ORDER BY name ASC, code ASC")->fetchAll(PDO::FETCH_ASSOC);
    $itemCategories = $pdo->query("SELECT * FROM inventory_item_categories WHERE is_active=1 ORDER BY category_name ASC")->fetchAll(PDO::FETCH_ASSOC);
    $units = $pdo->query("SELECT * FROM inventory_units WHERE is_active=1 ORDER BY unit_name ASC")->fetchAll(PDO::FETCH_ASSOC);
    $items = $pdo->query("
        SELECT ii.*, c.category_name, u.unit_code
        FROM inventory_items ii
        LEFT JOIN inventory_item_categories c ON c.id = ii.category_id
        LEFT JOIN inventory_units u ON u.id = ii.unit_id
        WHERE ii.is_active=1 AND ii.is_stock_item=1
        ORDER BY c.category_name ASC, ii.item_name ASC
    ")->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
    $errors[] = 'Could not load purchase order form data: ' . $e->getMessage();
}

$dateFrom = trim((string)($_GET['date_from'] ?? date('Y-m-01')));
$dateTo = trim((string)($_GET['date_to'] ?? date('Y-m-d')));
$status = trim((string)($_GET['status'] ?? ''));
$supplierFilter = (int)($_GET['supplier_id'] ?? 0);
$storeFilter = (int)($_GET['store_id'] ?? 0);
$search = trim((string)($_GET['q'] ?? ''));

if (strtotime($dateFrom) === false) $dateFrom = date('Y-m-01');
if (strtotime($dateTo) === false) $dateTo = date('Y-m-d');

$where = "po.po_date BETWEEN :date_from AND :date_to";
$params = [':date_from' => $dateFrom, ':date_to' => $dateTo];

if ($status !== '') { $where .= " AND po.status = :status"; $params[':status'] = $status; }
if ($supplierFilter > 0) { $where .= " AND po.supplier_id = :supplier_id"; $params[':supplier_id'] = $supplierFilter; }
if ($storeFilter > 0) { $where .= " AND po.store_id = :store_id"; $params[':store_id'] = $storeFilter; }
if ($search !== '') {
    $where .= " AND (po.po_no LIKE :q OR po.supplier_name LIKE :q OR sl.location_name LIKE :q)";
    $params[':q'] = '%' . $search . '%';
}

$purchaseOrders = [];
$summary = ['count'=>0,'draft'=>0,'approved'=>0,'part_received'=>0,'received'=>0,'cancelled'=>0,'total'=>0];

try {
    $stmt = $pdo->prepare("
        SELECT
            po.*,
            sl.location_name,
            COUNT(pol.id) AS line_count,
            COALESCE(SUM(pol.qty_ordered),0) AS ordered_qty,
            COALESCE(SUM(pol.qty_received),0) AS received_qty
        FROM inventory_purchase_orders po
        INNER JOIN store_locations sl ON sl.id = po.store_id
        LEFT JOIN inventory_purchase_order_lines pol ON pol.po_id = po.id
        WHERE $where
        GROUP BY po.id
        ORDER BY po.po_date DESC, po.id DESC
        LIMIT 300
    ");
    $stmt->execute($params);
    $purchaseOrders = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($purchaseOrders as $po) {
        $summary['count']++;
        if (isset($summary[$po['status']])) $summary[$po['status']]++;
        if (!in_array($po['status'], ['cancelled','void'], true)) $summary['total'] += (float)$po['total_amount'];
    }
} catch (Throwable $e) {
    $errors[] = 'Could not load purchase orders: ' . $e->getMessage();
}

$viewId = (int)($_GET['view_id'] ?? 0);
$viewPo = null;
$viewLines = [];
$viewGrns = [];

if ($viewId > 0) {
    try {
        $stmt = $pdo->prepare("
            SELECT po.*, sl.location_name
            FROM inventory_purchase_orders po
            INNER JOIN store_locations sl ON sl.id = po.store_id
            WHERE po.id = :id
            LIMIT 1
        ");
        $stmt->execute([':id' => $viewId]);
        $viewPo = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;

        if ($viewPo) {
            $stmt = $pdo->prepare("
                SELECT pol.*, ii.item_name, ii.item_code, u.unit_code, t.name AS tax_name, t.code AS tax_code, t.type AS tax_type
                FROM inventory_purchase_order_lines pol
                INNER JOIN inventory_items ii ON ii.id = pol.item_id
                LEFT JOIN inventory_units u ON u.id = ii.unit_id
                LEFT JOIN taxes t ON t.id = pol.tax_id
                WHERE pol.po_id = :po_id
                ORDER BY pol.id ASC
            ");
            $stmt->execute([':po_id' => $viewId]);
            $viewLines = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $stmt = $pdo->prepare("SELECT * FROM inventory_grns WHERE po_id = :po_id ORDER BY grn_date DESC, id DESC");
            $stmt->execute([':po_id' => $viewId]);
            $viewGrns = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
    } catch (Throwable $e) {
        $errors[] = 'Could not load PO detail: ' . $e->getMessage();
    }
}


$editId = (int)($_GET['edit_id'] ?? 0);
$editPo = null;
$editLines = [];
if ($editId > 0) {
    try {
        $stmt = $pdo->prepare("SELECT * FROM inventory_purchase_orders WHERE id=:id AND status='draft' LIMIT 1");
        $stmt->execute([':id'=>$editId]);
        $editPo = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
        if ($editPo) {
            $stmt = $pdo->prepare("SELECT * FROM inventory_purchase_order_lines WHERE po_id=:po_id ORDER BY id ASC");
            $stmt->execute([':po_id'=>$editId]);
            $editLines = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
    } catch (Throwable $e) { $errors[] = 'Could not load draft for editing: '.$e->getMessage(); }
}

$exportQuery = $_GET;
unset($exportQuery['view_id']);
$exportQuery['export'] = 'excel';
$exportUrl = 'purchase_orders.php?' . http_build_query($exportQuery);

if (($_GET['export'] ?? '') === 'excel') {
    try {
        $stmt = $pdo->prepare("
            SELECT
                po.po_date,
                po.expected_date,
                po.po_no,
                po.supplier_name,
                sl.location_name,
                po.status,
                COUNT(pol.id) AS line_count,
                COALESCE(SUM(pol.qty_ordered),0) AS ordered_qty,
                COALESCE(SUM(pol.qty_received),0) AS received_qty,
                po.subtotal,
                po.tax_amount,
                po.total_amount,
                po.notes,
                po.created_at,
                po.approved_at,
                po.cancelled_reason
            FROM inventory_purchase_orders po
            INNER JOIN store_locations sl ON sl.id = po.store_id
            LEFT JOIN inventory_purchase_order_lines pol ON pol.po_id = po.id
            WHERE $where
            GROUP BY po.id
            ORDER BY po.po_date DESC, po.id DESC
        ");
        $stmt->execute($params);
        $exportRows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $filename = 'purchase_orders_' . date('Ymd_His') . '.xls';
        header('Content-Type: application/vnd.ms-excel; charset=UTF-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Pragma: no-cache');
        header('Expires: 0');

        echo "\xEF\xBB\xBF";
        echo '<html><head><meta charset="UTF-8"><style>';
        echo 'table{border-collapse:collapse;font-family:Arial,sans-serif;font-size:11px;}';
        echo 'th{background:#1f2937;color:#ffffff;font-weight:bold;}';
        echo 'th,td{border:1px solid #d1d5db;padding:6px;}';
        echo '.right{text-align:right;} .center{text-align:center;} .title{font-size:18px;font-weight:bold;}';
        echo '

</style></head><body>';
        echo '<div class="title">Purchase Orders Export</div>';
        echo '<div>Generated: ' . h(date('Y-m-d H:i:s')) . '</div>';
        echo '<div>Filters: From ' . h($dateFrom) . ' To ' . h($dateTo) . ' | Status: ' . h($status ?: 'All') . ' | Search: ' . h($search ?: 'All') . '</div><br>';
        echo '<table>';
        echo '<thead><tr>';
        foreach (['PO Date','Expected Date','PO No','Supplier','Store','Status','Lines','Ordered Qty','Received Qty','Subtotal','Tax','Total','Notes','Created At','Approved At','Cancel Reason'] as $head) {
            echo '<th>' . h($head) . '</th>';
        }
        echo '</tr></thead><tbody>';
        if (!$exportRows) {
            echo '<tr><td colspan="16" class="center">No purchase orders found.</td></tr>';
        } else {
            foreach ($exportRows as $row) {
                echo '<tr>';
                echo '<td>' . h($row['po_date']) . '</td>';
                echo '<td>' . h($row['expected_date'] ?: '') . '</td>';
                echo '<td>' . h($row['po_no']) . '</td>';
                echo '<td>' . h($row['supplier_name']) . '</td>';
                echo '<td>' . h($row['location_name']) . '</td>';
                echo '<td>' . h(ucwords(str_replace('_', ' ', (string)$row['status']))) . '</td>';
                echo '<td class="right">' . h((int)$row['line_count']) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['ordered_qty'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['received_qty'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['subtotal'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['tax_amount'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['total_amount'])) . '</td>';
                echo '<td>' . h($row['notes'] ?: '') . '</td>';
                echo '<td>' . h($row['created_at'] ?: '') . '</td>';
                echo '<td>' . h($row['approved_at'] ?: '') . '</td>';
                echo '<td>' . h($row['cancelled_reason'] ?: '') . '</td>';
                echo '</tr>';
            }
        }
        echo '</tbody></table></body></html>';
        exit;
    } catch (Throwable $e) {
        po_flash('danger', 'Could not export purchase orders: ' . $e->getMessage());
        header('Location: purchase_orders.php');
        exit;
    }
}

$flashes = po_get_flash();

function po_status_badge(string $status): string {
    if ($status === 'draft') return 'text-bg-secondary';
    if ($status === 'approved') return 'text-bg-primary';
    if ($status === 'part_received') return 'text-bg-warning';
    if ($status === 'received') return 'text-bg-success';
    if (in_array($status, ['cancelled','void'], true)) return 'text-bg-danger';
    return 'text-bg-light';
}

require_once __DIR__ . '/../../includes/header.php';
?>

<div class="hero-band">
    <div class="row g-4 align-items-center">
        <div class="col-lg-8">
            <div class="page-eyebrow text-white-50"><i class="bi bi-clipboard-plus"></i> Stores &amp; POS Inventory</div>
            <div class="hero-title mt-2">Purchase Orders</div>
            <div class="hero-subtitle mt-2">
                Order stock from suppliers, approve purchase orders, and receive them into GRNs and stock movements.
            </div>
        </div>
        <div class="col-lg-4 text-lg-end">
            <a href="grn.php" class="btn btn-light me-2"><i class="bi bi-truck me-2"></i>GRN / Purchases</a>
            <a href="suppliers.php" class="btn btn-outline-light"><i class="bi bi-people me-2"></i>Suppliers</a>
        </div>
    </div>
</div>

<?php foreach ($flashes as $flash): ?>
    <div class="alert alert-<?php echo h($flash['type']); ?>"><?php echo h($flash['message']); ?></div>
<?php endforeach; ?>

<?php if ($errors): ?>
    <div class="alert alert-danger">
        <div class="fw-bold mb-2">Please fix the following:</div>
        <ul class="mb-0"><?php foreach ($errors as $err): ?><li><?php echo h($err); ?></li><?php endforeach; ?></ul>
    </div>
<?php endif; ?>

<div class="row g-4 mb-4">
    <div class="col-md-6 col-xl-3"><div class="metric-card"><div class="metric-icon bg-primary-subtle text-primary"><i class="bi bi-clipboard"></i></div><div><div class="metric-label">POs</div><div class="metric-value"><?php echo (int)$summary['count']; ?></div></div></div></div>
    <div class="col-md-6 col-xl-3"><div class="metric-card"><div class="metric-icon bg-info-subtle text-info"><i class="bi bi-check2-circle"></i></div><div><div class="metric-label">Approved</div><div class="metric-value"><?php echo (int)$summary['approved']; ?></div></div></div></div>
    <div class="col-md-6 col-xl-3"><div class="metric-card"><div class="metric-icon bg-success-subtle text-success"><i class="bi bi-box-arrow-in-down"></i></div><div><div class="metric-label">Received</div><div class="metric-value"><?php echo (int)$summary['received']; ?></div></div></div></div>
    <div class="col-md-6 col-xl-3"><div class="metric-card"><div class="metric-icon bg-warning-subtle text-warning"><i class="bi bi-cash-stack"></i></div><div><div class="metric-label">PO Value</div><div class="metric-value small-value"><?php echo money_fmt($summary['total']); ?></div></div></div></div>
</div>

<?php if ($viewPo): ?>
<div class="card panel-card mb-4 po-view" id="poView">
    <div class="card-header d-flex justify-content-between align-items-center">
        <h5 class="mb-0"><?php echo h($viewPo['po_no']); ?></h5>
        <div class="d-flex gap-2">
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="window.print()"><i class="bi bi-printer me-1"></i>Print</button>
            <a href="purchase_orders.php" class="btn btn-sm btn-outline-secondary">Close</a>
        </div>
    </div>
    <div class="card-body">
        <div class="row g-3 mb-3">
            <div class="col-md-3"><strong>Supplier:</strong><br><?php echo h($viewPo['supplier_name']); ?></div>
            <div class="col-md-3"><strong>Store:</strong><br><?php echo h($viewPo['location_name']); ?></div>
            <div class="col-md-2"><strong>Date:</strong><br><?php echo h($viewPo['po_date']); ?></div>
            <div class="col-md-2"><strong>Expected:</strong><br><?php echo h($viewPo['expected_date'] ?: '—'); ?></div>
            <div class="col-md-2"><strong>Status:</strong><br><span class="badge <?php echo h(po_status_badge($viewPo['status'])); ?>"><?php echo h(ucwords(str_replace('_',' ', $viewPo['status']))); ?></span></div>
        </div>

        <?php if (!empty($viewPo['notes'])): ?><div class="alert alert-info"><?php echo h($viewPo['notes']); ?></div><?php endif; ?>

        <div class="table-responsive">
            <table class="table table-sm align-middle">
                <thead><tr><th>Item</th><th class="text-end">Ordered</th><th class="text-end">Received</th><th class="text-end">Remaining</th><th class="text-end">Unit Price</th><th>VAT Mode</th><th>Tax Line</th><th class="text-end">Total</th></tr></thead>
                <tbody>
                <?php foreach ($viewLines as $line): ?>
                    <?php $remaining = max(0, (float)$line['qty_ordered'] - (float)$line['qty_received']); ?>
                    <tr>
                        <td><strong><?php echo h($line['item_name']); ?></strong><div class="small text-muted"><?php echo h($line['item_code'] ?: ''); ?> <?php echo h($line['unit_code'] ?: ''); ?></div></td>
                        <td class="text-end"><?php echo money_fmt($line['qty_ordered']); ?></td>
                        <td class="text-end"><?php echo money_fmt($line['qty_received']); ?></td>
                        <td class="text-end fw-bold"><?php echo money_fmt($remaining); ?></td>
                        <td class="text-end">
                            <?php echo money_fmt(($line['unit_price_entered'] ?? 0) ?: $line['unit_cost']); ?>
                            <div class="small text-muted">Stock cost <?php echo money_fmt($line['unit_cost']); ?></div>
                        </td>
                        <td><?php echo h(ucwords((string)($line['price_tax_mode'] ?? 'exclusive'))); ?></td>
                        <td>
                            <?php echo h($line['tax_name'] ?: 'No Tax'); ?>
                            <div class="small text-muted"><?php echo h($line['tax_code'] ?: ''); ?> <?php echo !empty($line['tax_type']) ? h($line['tax_type'] . ' ' . money_fmt($line['tax_rate'])) : ''; ?></div>
                        </td>
                        <td class="text-end fw-bold"><?php echo money_fmt($line['line_total']); ?></td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
                <tfoot>
                    <tr><th colspan="7" class="text-end">Subtotal</th><th class="text-end"><?php echo money_fmt($viewPo['subtotal']); ?></th></tr>
                    <tr><th colspan="7" class="text-end">Tax</th><th class="text-end"><?php echo money_fmt($viewPo['tax_amount']); ?></th></tr>
                    <tr><th colspan="7" class="text-end fs-5">Total</th><th class="text-end fs-5"><?php echo money_fmt($viewPo['total_amount']); ?></th></tr>
                </tfoot>
            </table>
        </div>

        <?php if ($viewGrns): ?>
            <h6 class="fw-bold mt-4">GRNs from this PO</h6>
            <div class="table-responsive">
                <table class="table table-sm">
                    <thead><tr><th>Date</th><th>GRN</th><th>Invoice</th><th>Status</th><th class="text-end">Total</th><th></th></tr></thead>
                    <tbody>
                    <?php foreach ($viewGrns as $g): ?>
                        <tr>
                            <td><?php echo h($g['grn_date']); ?></td>
                            <td><strong><?php echo h($g['grn_no']); ?></strong></td>
                            <td><?php echo h($g['invoice_no'] ?: '—'); ?></td>
                            <td><span class="badge <?php echo $g['status'] === 'posted' ? 'text-bg-success' : 'text-bg-danger'; ?>"><?php echo h(ucwords($g['status'])); ?></span></td>
                            <td class="text-end"><?php echo money_fmt($g['total_amount']); ?></td>
                            <td class="text-end"><a href="grn.php?view_id=<?php echo (int)$g['id']; ?>" class="btn btn-sm btn-outline-primary"><i class="bi bi-eye"></i></a></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        <?php endif; ?>

        <div class="po-actions mt-4">
            <?php if ($viewPo['status'] === 'draft'): ?>
                <a href="purchase_orders.php?edit_id=<?php echo (int)$viewPo['id']; ?>" class="btn btn-primary"><i class="bi bi-pencil-square me-2"></i>Edit Draft</a>
                <form method="post" onsubmit="return confirm('Approve this purchase order?');">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="approve_po">
                    <input type="hidden" name="po_id" value="<?php echo (int)$viewPo['id']; ?>">
                    <button class="btn btn-success"><i class="bi bi-check2-circle me-2"></i>Approve PO</button>
                </form>
            <?php endif; ?>

            <?php if (in_array($viewPo['status'], ['draft','approved'], true)): ?>
                <form method="post" class="cancel-form" onsubmit="return confirm('Cancel this purchase order?');">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="cancel_po">
                    <input type="hidden" name="po_id" value="<?php echo (int)$viewPo['id']; ?>">
                    <div class="input-group">
                        <input type="text" name="cancelled_reason" class="form-control" placeholder="Cancel reason">
                        <button class="btn btn-outline-danger"><i class="bi bi-x-octagon me-1"></i>Cancel</button>
                    </div>
                </form>
            <?php endif; ?>
        </div>

        <?php if (in_array($viewPo['status'], ['approved','part_received'], true)): ?>
            <div class="receive-box mt-4">
                <h6 class="fw-bold">Receive Into GRN</h6>
                <form method="post" onsubmit="return confirm('Receive selected quantities and create GRN?');">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="receive_po">
                    <input type="hidden" name="po_id" value="<?php echo (int)$viewPo['id']; ?>">

                    <div class="row g-3 mb-3">
                        <div class="col-md-4">
                            <label class="form-label">GRN Date</label>
                            <input type="date" name="grn_date" class="form-control" value="<?php echo h(date('Y-m-d')); ?>">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Supplier Invoice No</label>
                            <input type="text" name="invoice_no" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Notes</label>
                            <input type="text" name="receive_notes" class="form-control">
                        </div>
                    </div>

                    <div class="table-responsive">
                        <table class="table table-sm" id="receiveGrnTable">
                            <thead><tr><th>Item</th><th class="text-end">Remaining</th><th class="text-end">Ordered @</th><th>Storage Area</th><th class="text-end">Receive Qty</th><th class="text-end">Actual Unit Price</th><th class="text-end">Amount</th></tr></thead>
                            <tbody>
                            <?php foreach ($viewLines as $line): ?>
                                <?php $remaining = max(0, (float)$line['qty_ordered'] - (float)$line['qty_received']); ?>
                                <?php if ($remaining <= 0) continue; ?>
                                <?php $poLinePrice = (float)(($line['unit_price_entered'] ?? 0) ?: ($line['unit_cost'] ?? 0)); ?>
                                <tr class="receive-line"
                                    data-tax-rate="<?php echo h(number_format((float)$line['tax_rate'], 4, '.', '')); ?>"
                                    data-tax-type="<?php echo h((string)($line['tax_type'] ?? 'Percentage')); ?>"
                                    data-tax-mode="<?php echo h((string)($line['price_tax_mode'] ?? 'exclusive')); ?>">
                                    <td><?php echo h($line['item_name']); ?></td>
                                    <td class="text-end"><?php echo money_fmt($remaining); ?></td>
                                    <td class="text-end text-muted"><?php echo money_fmt($poLinePrice); ?></td>
                                    <td style="min-width:190px;">
                                        <select
                                            name="receive_store_id[<?php echo (int)$line['id']; ?>]"
                                            class="form-select form-select-sm receive-store"
                                            title="Choose where this item will be received. Defaults to the PO receiving store."
                                        >
                                            <?php foreach ($stores as $store): ?>
                                                <option
                                                    value="<?php echo (int)$store['id']; ?>"
                                                    <?php echo (int)$store['id'] === (int)$viewPo['store_id'] ? 'selected' : ''; ?>
                                                >
                                                    <?php echo h($store['location_name']); ?>
                                                </option>
                                            <?php endforeach; ?>
                                        </select>
                                        <div class="form-text">Defaults to <?php echo h($viewPo['location_name']); ?></div>
                                    </td>
                                    <td class="text-end" style="max-width:110px;">
                                        <input type="number" step="0.0001" min="0" max="<?php echo h(number_format($remaining, 4, '.', '')); ?>" name="receive_qty[<?php echo (int)$line['id']; ?>]" class="form-control form-control-sm text-end receive-qty" value="<?php echo h(rtrim(rtrim(number_format($remaining, 4, '.', ''), '0'), '.')); ?>">
                                    </td>
                                    <td class="text-end" style="max-width:130px;">
                                        <input type="number" step="any" min="0" name="receive_price[<?php echo (int)$line['id']; ?>]" class="form-control form-control-sm text-end receive-price" value="<?php echo h(number_format($poLinePrice, 4, '.', '')); ?>" title="The price actually charged on delivery - change it here if it differs from the PO. The GRN and stock cost use this price.">
                                    </td>
                                    <td class="text-end" style="max-width:130px;">
                                        <input type="number" step="any" min="0" name="receive_amount[<?php echo (int)$line['id']; ?>]" class="form-control form-control-sm text-end receive-amount" value="<?php echo h(number_format(round($remaining * $poLinePrice, 2), 2, '.', '')); ?>" title="Type the delivery invoice line amount here and the actual unit price is calculated back (amount ÷ qty). It fills automatically from qty × price.">
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>
                    <div class="row justify-content-end mb-3">
                        <div class="col-md-6 col-lg-5">
                            <div class="card border-0 bg-light receive-summary-card">
                                <div class="card-body py-3">
                                    <div class="d-flex justify-content-between mb-2">
                                        <span class="text-muted">Receive Subtotal</span>
                                        <strong id="receiveSummarySubtotal">0.00</strong>
                                    </div>
                                    <div class="d-flex justify-content-between mb-2">
                                        <span class="text-muted">Receive Tax</span>
                                        <strong id="receiveSummaryTax">0.00</strong>
                                    </div>
                                    <div class="d-flex justify-content-between border-top pt-2 fs-5">
                                        <span class="fw-bold">Receive Total</span>
                                        <strong id="receiveSummaryTotal">0.00</strong>
                                    </div>
                                    <div class="small text-muted mt-2">
                                        This summary reflects only the quantities and actual prices being received into this GRN.
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="small text-muted mb-2">
                        <strong>Storage Area:</strong> each line defaults to the PO receiving store, but you may override it so one GRN can receive different items into different stores.
                        Actual Unit Price defaults to the PO price - change it (or type the invoice line Amount) when the supplier's delivered price differs. The GRN, stock movement cost, and average cost all use the actual figures.
                    </div>

                    <button class="btn btn-primary"><i class="bi bi-box-arrow-in-down me-2"></i>Receive & Create GRN</button>
                </form>
            </div>
        <?php endif; ?>
    </div>
</div>
<?php endif; ?>

<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
    <div>
        <h5 class="mb-1">Purchase Order History</h5>
        <div class="small text-muted">Create POs in a focused full-screen window. Drafts can be reopened and continued later.</div>
    </div>
    <button type="button" class="btn btn-primary" id="openPoModal"><i class="bi bi-plus-circle me-2"></i>New Purchase Order</button>
</div>

<div class="card panel-card mb-4">
    <div class="card-body">
        <form method="get" class="row g-2 align-items-end">
            <div class="col-md-2"><label class="form-label">From</label><input type="date" name="date_from" class="form-control" value="<?php echo h($dateFrom); ?>"></div>
            <div class="col-md-2"><label class="form-label">To</label><input type="date" name="date_to" class="form-control" value="<?php echo h($dateTo); ?>"></div>
            <div class="col-md-2"><label class="form-label">Supplier</label><select name="supplier_id" class="form-select supplier-filter-select search-select" data-search-placeholder="All / search supplier"><option value="0">All suppliers</option><?php foreach ($suppliers as $s): ?><option value="<?php echo (int)$s['id']; ?>" <?php echo $supplierFilter === (int)$s['id'] ? 'selected' : ''; ?> data-subtext="<?php echo h(trim(($s['supplier_code'] ?? '') . (($s['phone'] ?? '') ? ' • ' . $s['phone'] : ''))); ?>"><?php echo h($s['supplier_name']); ?></option><?php endforeach; ?></select></div>
            <div class="col-md-2"><label class="form-label">Store</label><select name="store_id" class="form-select"><option value="0">All</option><?php foreach ($stores as $s): ?><option value="<?php echo (int)$s['id']; ?>" <?php echo $storeFilter === (int)$s['id'] ? 'selected' : ''; ?>><?php echo h($s['location_name']); ?></option><?php endforeach; ?></select></div>
            <div class="col-md-2"><label class="form-label">Status</label><select name="status" class="form-select"><option value="">All</option><?php foreach (['draft','approved','part_received','received','cancelled'] as $st): ?><option value="<?php echo h($st); ?>" <?php echo $status === $st ? 'selected' : ''; ?>><?php echo h(ucwords(str_replace('_',' ', $st))); ?></option><?php endforeach; ?></select></div>
            <div class="col-md-1"><label class="form-label">Search</label><input type="text" name="q" class="form-control" value="<?php echo h($search); ?>"></div>
            <div class="col-md-1 d-grid"><button class="btn btn-primary"><i class="bi bi-funnel"></i></button></div>
        </form>
    </div>
</div>

<div class="card panel-card">
    <div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
        <span class="text-muted small">Showing latest 300 matching POs</span>
        <a href="<?php echo h($exportUrl); ?>" class="btn btn-sm btn-success"><i class="bi bi-file-earmark-excel me-1"></i>Export Excel</a>
    </div>
    <div class="card-body p-0"><div class="po-history-table-wrap">
        <table class="table table-modern align-middle mb-0 po-history-table">
            <thead><tr><th>PO / Date</th><th>Supplier / Store</th><th>Status</th><th class="text-end">Qty</th><th class="text-end">Total</th><th class="text-end">Actions</th></tr></thead>
            <tbody>
            <?php if (!$purchaseOrders): ?><tr><td colspan="6" class="text-center text-muted py-4">No purchase orders found.</td></tr>
            <?php else: foreach ($purchaseOrders as $po): ?>
                <tr>
                    <td><strong><?php echo h($po['po_no']); ?></strong><div class="small text-muted"><?php echo h($po['po_date']); ?> • <?php echo (int)$po['line_count']; ?> line(s)</div></td>
                    <td><?php echo h($po['supplier_name']); ?><div class="small text-muted"><?php echo h($po['location_name']); ?></div></td>
                    <td><span class="badge <?php echo h(po_status_badge($po['status'])); ?>"><?php echo h(ucwords(str_replace('_',' ', $po['status']))); ?></span></td>
                    <td class="text-end"><?php echo money_fmt($po['received_qty']); ?><div class="small text-muted">of <?php echo money_fmt($po['ordered_qty']); ?></div></td>
                    <td class="text-end fw-bold"><?php echo money_fmt($po['total_amount']); ?></td>
                    <td class="text-end text-nowrap">
                        <?php if ($po['status']==='draft'): ?><a href="purchase_orders.php?edit_id=<?php echo (int)$po['id']; ?>" class="btn btn-sm btn-outline-primary" title="Continue draft"><i class="bi bi-pencil-square"></i></a><?php endif; ?>
                        <a href="purchase_orders.php?view_id=<?php echo (int)$po['id']; ?>" class="btn btn-sm btn-outline-secondary" title="View"><i class="bi bi-eye"></i></a>
                    </td>
                </tr>
            <?php endforeach; endif; ?>
            </tbody>
        </table>
    </div></div>
</div>

<div class="modal fade po-workspace-modal" id="poModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static">
  <div class="modal-dialog modal-dialog-centered po-workspace-dialog">
    <div class="modal-content po-workspace-shell">
      <div class="po-workspace-header">
        <div class="po-title-group">
          <div class="po-title-icon"><i class="bi bi-clipboard2-check"></i></div>
          <div>
            <h4 class="mb-1"><?php echo $editPo ? 'Continue Draft '.h($editPo['po_no']) : 'Create Purchase Order'; ?></h4>
            <div class="po-title-sub">Enter supplier, delivery details and items. Save as draft at any time.</div>
          </div>
        </div>
        <div class="po-header-actions">
          <span class="po-draft-pill"><i class="bi bi-file-earmark-text"></i> Draft</span>
          <button type="button" class="po-icon-btn" data-bs-dismiss="modal" aria-label="Close"><i class="bi bi-x-lg"></i></button>
        </div>
      </div>

      <form method="post" id="poForm" class="po-workspace-form">
        <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
        <input type="hidden" name="action" value="create_po">
        <input type="hidden" name="po_id" value="<?php echo (int)($editPo['id'] ?? 0); ?>">

        <div class="po-workspace-body">
          <section class="po-card po-details-card">
            <div class="po-details-grid">
              <div class="po-field po-field-supplier">
                <label class="form-label">Supplier <span>*</span></label>
                <select name="supplier_id" class="form-select supplier-select search-select" data-search-placeholder="Search supplier..." required>
                  <option value="">Select supplier</option>
                  <?php foreach ($suppliers as $supplier): ?>
                    <option value="<?php echo (int)$supplier['id']; ?>" <?php echo ((int)($editPo['supplier_id'] ?? 0)===(int)$supplier['id'])?'selected':''; ?> data-subtext="<?php echo h(trim(($supplier['supplier_code'] ?? '') . (($supplier['phone'] ?? '') ? ' • ' . $supplier['phone'] : ''))); ?>"><?php echo h($supplier['supplier_name']); ?></option>
                  <?php endforeach; ?>
                </select>
                <a href="suppliers.php" class="po-inline-link"><i class="bi bi-plus"></i>Add New Supplier</a>
              </div>
              <div class="po-field">
                <label class="form-label">Receiving Store <span>*</span></label>
                <select name="store_id" class="form-select" required>
                  <option value="">Select store</option>
                  <?php foreach ($stores as $store): ?><option value="<?php echo (int)$store['id']; ?>" <?php echo ((int)($editPo['store_id'] ?? 0)===(int)$store['id'])?'selected':''; ?>><?php echo h($store['location_name']); ?></option><?php endforeach; ?>
                </select>
              </div>
              <div class="po-field">
                <label class="form-label">PO Date <span>*</span></label>
                <input type="date" name="po_date" class="form-control" value="<?php echo h($editPo['po_date'] ?? date('Y-m-d')); ?>">
              </div>
              <div class="po-field">
                <label class="form-label">Expected Date</label>
                <input type="date" name="expected_date" class="form-control" value="<?php echo h($editPo['expected_date'] ?? ''); ?>">
              </div>
            </div>
            <div class="po-notes-wrap">
              <div class="po-notes-icon"><i class="bi bi-chat-left-text"></i></div>
              <div class="flex-grow-1">
                <label class="form-label">Notes</label>
                <textarea name="notes" class="form-control" rows="2" placeholder="Add notes or additional information (optional)"><?php echo h($editPo['notes'] ?? ''); ?></textarea>
              </div>
            </div>
          </section>

          <section class="po-card po-lines-card">
            <div class="po-lines-head">
              <div><h5 class="mb-0">Purchase Order Lines <span class="po-count" id="lineCount">0</span></h5></div>
              <div class="po-lines-actions">
                <button type="button" class="btn po-btn-secondary" id="openQuickItem"><i class="bi bi-box-seam"></i>Add Missing Item</button>
                <button type="button" class="btn po-btn-primary" id="addLine"><i class="bi bi-plus-lg"></i>Add Item</button>
              </div>
            </div>
            <div class="po-lines-layout">
              <div class="po-lines-main">
                <div class="po-global-search"><i class="bi bi-search"></i><input type="text" id="poGlobalItemSearch" placeholder="Search item by name, code or barcode..."></div>
                <div class="po-grid-header"><span>#</span><span>Item</span><span>Qty</span><span>Unit Price</span><span>VAT Mode</span><span>Tax Line</span><span>Line Amount</span><span></span></div>
                <div id="lineBox" class="po-lines"></div>
              </div>
              <aside class="po-summary-card">
                <h5>Summary</h5>
                <div class="po-summary-row"><span>Subtotal</span><strong id="subtotalLabel">0.00</strong></div>
                <div class="po-summary-row"><span>Tax</span><strong id="taxLabel">0.00</strong></div>
                <div class="po-summary-total"><span>Total</span><strong id="totalLabel">0.00</strong></div>
              </aside>
            </div>
          </section>
        </div>

        <div class="po-workspace-footer">
          <div class="po-footer-left">
            <button type="button" class="btn po-btn-cancel" data-bs-dismiss="modal"><i class="bi bi-x-lg"></i>Cancel</button>
            <button type="button" class="btn po-btn-clear" id="clearPoLines"><i class="bi bi-arrow-counterclockwise"></i>Clear All</button>
          </div>
          <div class="po-footer-right">
            <button class="btn po-save-draft" name="submit_mode" value="draft"><i class="bi bi-file-earmark-arrow-down"></i>Save Draft</button>
            <button class="btn po-save-approve" name="submit_mode" value="approve" onclick="return confirm('Save and approve this purchase order?');"><i class="bi bi-check2"></i>Save &amp; Approve</button>
          </div>
        </div>
        <div class="po-keyboard-tip"><span><i class="bi bi-lightbulb"></i> Tip:</span> Use <kbd>TAB</kbd> to move between fields. Press <kbd>ENTER</kbd> in item search to select.</div>
      </form>
    </div>
  </div>
</div>

<div class="modal fade" id="quickItemModal" tabindex="-1" aria-hidden="true"><div class="modal-dialog modal-dialog-centered"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Add Missing Inventory Item</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><form id="quickItemForm"><div class="modal-body"><div class="row g-2"><div class="col-8"><label class="form-label">Item Name</label><input name="item_name" class="form-control" required></div><div class="col-4"><label class="form-label">Item Code</label><input name="item_code" class="form-control"></div><div class="col-6"><label class="form-label">Category</label><select name="category_id" class="form-select"><option value="0">None</option><?php foreach($itemCategories as $c): ?><option value="<?php echo (int)$c['id']; ?>"><?php echo h($c['category_name']); ?></option><?php endforeach; ?></select></div><div class="col-6"><label class="form-label">Unit</label><select name="unit_id" class="form-select"><option value="0">None</option><?php foreach($units as $u): ?><option value="<?php echo (int)$u['id']; ?>"><?php echo h($u['unit_name']); ?> (<?php echo h($u['unit_code']); ?>)</option><?php endforeach; ?></select></div><div class="col-6"><label class="form-label">Cost Price</label><input type="number" step="any" min="0" name="cost_price" class="form-control" value="0"></div><div class="col-6"><label class="form-label">Tax Rate %</label><input type="number" step="any" min="0" name="tax_rate" class="form-control" value="0"></div></div><div class="alert alert-danger py-2 mt-3 d-none" id="quickItemError"></div></div><div class="modal-footer"><button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button><button class="btn btn-success">Save Item & Add to PO</button></div></form></div></div></div>

<template id="lineTemplate">
  <div class="po-line">
    <div class="po-line-index">1</div>
    <div class="po-line-item">
      <select name="item_id[]" class="form-select item-select search-select" required>
        <option value="">Select item</option>
        <?php foreach ($items as $item): ?>
          <option value="<?php echo (int)$item['id']; ?>" data-cost="<?php echo h($item['avg_cost'] ?: $item['cost_price']); ?>" data-tax="<?php echo h($item['tax_rate']); ?>"><?php echo h($item['item_name']); ?><?php echo $item['item_code'] ? ' - ' . h($item['item_code']) : ''; ?> <?php echo $item['unit_code'] ? '(' . h($item['unit_code']) . ')' : ''; ?></option>
        <?php endforeach; ?>
      </select>
      <div class="line-total">Net: 0.00 | VAT: 0.00 | Total: 0.00 | Stock cost: 0.0000</div>
    </div>
    <div><input type="number" step="0.001" min="1" name="qty_ordered[]" class="form-control qty-input" value="1"></div>
    <div><input type="number" step="any" min="0" name="unit_cost[]" class="form-control cost-input" value="0"></div>
    <div><select name="price_tax_mode[]" class="form-select price-tax-mode"><option value="exclusive">Exclusive</option><option value="inclusive">Inclusive</option></select></div>
    <div><select name="tax_id[]" class="form-select tax-select"><option value="" data-rate="0" data-type="Percentage">No Tax</option><?php foreach ($taxes as $tax): ?><option value="<?php echo (int)$tax['id']; ?>" data-rate="<?php echo h($tax['rate']); ?>" data-type="<?php echo h($tax['type']); ?>"><?php echo h($tax['name']); ?> (<?php echo h($tax['code']); ?>)</option><?php endforeach; ?></select></div>
    <div class="po-amount-wrap"><input type="number" step="any" min="0" name="line_amount[]" class="form-control amount-input" value="0.00"></div>
    <div><button type="button" class="btn remove-line" title="Remove line"><i class="bi bi-trash3"></i></button></div>
  </div>
</template>

<style>
.hero-band{padding:12px 16px!important;margin-bottom:10px!important}.hero-title{font-size:1.35rem!important}.hero-subtitle{font-size:.82rem!important}.row.g-4.mb-4{margin-bottom:10px!important}.metric-card{padding:9px 10px!important;min-height:58px!important}.metric-value{font-size:1rem!important}.panel-card .card-body{padding:10px!important}.po-history-table-wrap{max-height:calc(100vh - 255px);overflow:auto}.po-history-table thead th{position:sticky;top:0;z-index:10;background:#fff!important}
.po-workspace-modal{--bs-modal-zindex:1060}.po-workspace-modal.show{background:rgba(2,12,27,.58)}.modal-backdrop.show{opacity:.68!important;background:#061326!important}.po-workspace-dialog{width:min(1420px,calc(100vw - 42px));max-width:none;height:calc(100vh - 34px);margin:17px auto}.po-workspace-shell{height:100%;border:0;border-radius:18px;overflow:hidden;background:#f7f9fc;box-shadow:0 30px 90px rgba(2,12,27,.35)}
.po-workspace-header{height:88px;padding:18px 24px;display:flex;align-items:center;justify-content:space-between;background:#fff;border-bottom:1px solid #e7ebf2}.po-title-group{display:flex;align-items:center;gap:14px}.po-title-icon{width:44px;height:44px;border:1px solid #cfe0ff;border-radius:12px;display:grid;place-items:center;color:#0d6efd;background:#f4f8ff;font-size:20px}.po-title-group h4{font-weight:750;color:#101828}.po-title-sub{font-size:13px;color:#667085}.po-header-actions{display:flex;gap:10px;align-items:center}.po-draft-pill{height:40px;padding:0 14px;display:flex;align-items:center;gap:8px;border:1px solid #dfe5ee;border-radius:10px;background:#fff;color:#344054;font-weight:650}.po-icon-btn{width:40px;height:40px;border:0;background:transparent;border-radius:10px;color:#344054}.po-icon-btn:hover{background:#f2f4f7}
.po-workspace-form{height:calc(100% - 88px);display:flex;flex-direction:column;min-height:0}.po-workspace-body{padding:16px 20px;display:flex;flex-direction:column;gap:14px;min-height:0;flex:1}.po-card{background:#fff;border:1px solid #e3e8ef;border-radius:14px;box-shadow:0 2px 5px rgba(16,24,40,.03)}.po-details-card{padding:18px}.po-details-grid{display:grid;grid-template-columns:1.45fr 1.2fr .82fr .82fr;gap:18px}.po-field .form-label{font-size:12px;font-weight:700;color:#263145;margin-bottom:7px}.po-field .form-label span{color:#e5484d}.po-field .form-control,.po-field .form-select,.po-field .item-search-input{height:44px!important;border-radius:9px!important;border-color:#d8dee8!important;font-size:13px!important}.po-inline-link{font-size:12px;text-decoration:none;display:inline-flex;gap:4px;margin-top:7px}.po-notes-wrap{margin-top:14px;display:flex;gap:12px;align-items:flex-start;border:1px solid #e1e6ed;border-radius:10px;padding:10px 12px}.po-notes-icon{width:34px;height:34px;border-radius:8px;background:#f6f8fb;display:grid;place-items:center;color:#344054;margin-top:18px}.po-notes-wrap textarea{border:0!important;box-shadow:none!important;padding:4px 0!important;min-height:48px!important;resize:none;font-size:13px}
.po-lines-card{padding:16px;display:flex;flex-direction:column;min-height:0;flex:1}.po-lines-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.po-lines-head h5{font-size:16px;font-weight:750}.po-count{font-size:12px;background:#f2f4f7;border-radius:999px;padding:4px 8px;color:#475467}.po-lines-actions{display:flex;gap:10px}.po-lines-actions .btn{height:40px;border-radius:9px;padding:0 14px;font-size:13px;font-weight:650;display:flex;align-items:center;gap:7px}.po-btn-secondary{border:1px solid #d0d7e2;background:#fff;color:#175cd3}.po-btn-primary{background:#0d6efd;color:#fff}.po-lines-layout{display:grid;grid-template-columns:minmax(0,1fr) 250px;gap:16px;min-height:0;flex:1}.po-lines-main{min-width:0;min-height:0;display:flex;flex-direction:column}.po-global-search{height:42px;border:1px solid #d8dee8;border-radius:9px;display:flex;align-items:center;gap:9px;padding:0 13px;margin-bottom:10px;color:#667085}.po-global-search input{border:0;outline:0;width:100%;font-size:13px}.po-grid-header,.po-line{display:grid;grid-template-columns:34px minmax(250px,2fr) 90px 120px 130px 145px 130px 42px;gap:10px;align-items:center}.po-grid-header{height:38px;padding:0 10px;background:#f7f9fc;border:1px solid #e3e8ef;border-radius:9px 9px 0 0;color:#667085;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em}.po-lines{min-height:0;flex:1 1 auto;overflow:auto;border:1px solid #e3e8ef;border-top:0;border-radius:0 0 9px 9px;background:#fff}.po-line{padding:10px;border-bottom:1px solid #edf0f4;position:relative;min-width:1020px}.po-line:last-child{border-bottom:0}.po-line-index{text-align:center;font-weight:700;color:#344054}.po-line .form-control,.po-line .form-select,.po-line .item-search-input{height:40px!important;min-height:40px!important;border-radius:8px!important;font-size:12px!important;border-color:#d8dee8!important}.po-line .line-total{font-size:10px;color:#7a8699;margin-top:5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.remove-line{width:38px;height:38px;border:1px solid #f1c0c4;color:#d92d20;background:#fff;border-radius:8px}.remove-line:hover{background:#fff1f2;color:#b42318}.po-amount-wrap input{text-align:right;font-weight:700}.po-summary-card{align-self:start;border:1px solid #e1e7ef;border-radius:12px;background:#fbfcfe;overflow:hidden}.po-summary-card h5{padding:16px;margin:0;font-size:16px;font-weight:750}.po-summary-row{padding:8px 16px;display:flex;justify-content:space-between;font-size:13px}.po-summary-total{margin-top:8px;padding:16px;border-top:1px solid #dfe5ee;display:flex;justify-content:space-between;color:#0d6efd;font-size:17px;font-weight:750;background:#f3f7ff}
.po-workspace-footer{height:76px;padding:14px 20px;display:flex;align-items:center;justify-content:space-between;background:#fff;border-top:1px solid #e3e8ef}.po-footer-left,.po-footer-right{display:flex;gap:10px}.po-workspace-footer .btn{height:44px;border-radius:9px;padding:0 18px;font-size:13px;font-weight:700;display:flex;align-items:center;gap:8px}.po-btn-cancel,.po-btn-clear{background:#fff;border:1px solid #d0d7e2;color:#344054}.po-save-draft{background:#fff;border:1px solid #0d6efd;color:#0d6efd}.po-save-approve{background:#159455;border:1px solid #159455;color:#fff;min-width:190px;justify-content:center}.po-keyboard-tip{height:38px;background:#fbfcfe;border-top:1px solid #eef1f5;display:flex;justify-content:center;align-items:center;color:#667085;font-size:11px}.po-keyboard-tip span{color:#0d6efd;font-weight:700;margin-right:8px}.po-keyboard-tip kbd{font-size:10px;background:#fff;color:#344054;border:1px solid #d0d5dd;box-shadow:none;margin:0 4px}
select.search-select{position:absolute!important;left:-99999px!important;width:1px!important;height:1px!important;opacity:0!important}.item-search-wrap{position:relative;width:100%;z-index:20}.item-search-menu{position:fixed!important;z-index:2147483647!important;max-height:min(440px,55vh)!important;overflow-y:auto!important;overflow-x:hidden!important;background:#fff!important;border:1px solid #b8c4d4!important;border-radius:12px!important;box-shadow:0 24px 70px rgba(2,12,27,.38)!important;padding:6px!important;display:none!important;isolation:isolate!important;overscroll-behavior:contain}.item-search-menu.open{display:block!important}.item-search-option{padding:8px 10px;border-radius:7px;font-size:12px;cursor:pointer}.item-search-option:hover,.item-search-option.active{background:#eff6ff;color:#175cd3}.item-search-option .muted{display:block;font-size:10px;color:#667085;margin-top:2px}.item-search-empty{padding:10px;color:#667085;font-size:12px;text-align:center}.po-line:has(.item-search-wrap.open){z-index:100}.inventory-item-picker{padding:0!important;border-radius:16px!important;overflow-y:auto!important;background:#fff!important}.inventory-picker-head{position:sticky;top:0;z-index:3;display:flex;align-items:center;justify-content:space-between;padding:15px 18px;background:#0b2344;color:#fff;border-radius:15px 15px 0 0;box-shadow:0 2px 8px rgba(2,12,27,.18)}.inventory-picker-head strong{display:block;font-size:15px}.inventory-picker-head span{display:block;font-size:11px;opacity:.75;margin-top:2px}.inventory-picker-close{width:36px;height:36px;border:1px solid rgba(255,255,255,.28);border-radius:9px;background:rgba(255,255,255,.10);color:#fff;font-size:25px;line-height:1}.inventory-item-picker .item-search-option{margin:4px 8px;padding:11px 13px;border:1px solid #edf1f5;background:#fff}.inventory-item-picker .item-search-option:hover,.inventory-item-picker .item-search-option.active{border-color:#9ec5fe;background:#eef6ff}.inventory-item-picker .item-search-empty{padding:40px 20px;font-size:14px}
#quickItemModal .modal-content{border:0;border-radius:16px;box-shadow:0 24px 70px rgba(2,12,27,.3)}#quickItemModal .modal-header{padding:18px 20px}#quickItemModal .modal-body{padding:18px 20px}#quickItemModal .modal-footer{padding:14px 20px}
@media(max-width:1100px){.po-details-grid{grid-template-columns:1fr 1fr}.po-lines-layout{grid-template-columns:1fr}.po-summary-card{display:grid;grid-template-columns:1fr 1fr 1fr;align-items:center}.po-summary-card h5{display:none}.po-summary-total{margin:0;border-top:0;border-left:1px solid #dfe5ee}.po-workspace-dialog{width:100vw;height:100vh;margin:0}.po-workspace-shell{border-radius:0}}@media(max-width:700px){.po-workspace-header{padding:14px}.po-title-sub,.po-draft-pill{display:none}.po-workspace-body{padding:10px}.po-details-grid{grid-template-columns:1fr}.po-lines-actions{gap:6px}.po-lines-head{align-items:flex-start}.po-workspace-footer{height:auto;gap:10px;flex-direction:column}.po-footer-left,.po-footer-right{width:100%}.po-workspace-footer .btn{flex:1}.po-keyboard-tip{display:none}}
@media print{body *{visibility:hidden!important}#poView,#poView *{visibility:visible!important}#poView{position:absolute;left:0;top:0;width:100%}.po-actions,.receive-box,.hero-band,.panel-card:not(#poView){display:none!important}}
</style>

<script>
document.addEventListener('DOMContentLoaded', function(){
    const lineBox = document.getElementById('lineBox');
    const template = document.getElementById('lineTemplate');
    const addLineBtn = document.getElementById('addLine');
    const subtotalLabel = document.getElementById('subtotalLabel');
    const taxLabel = document.getElementById('taxLabel');
    const totalLabel = document.getElementById('totalLabel');
    const lineCount = document.getElementById('lineCount');

    function money(n){ return Number(n || 0).toFixed(2); }

    function initSearchSelect(context){
        const scope = context || document;
        scope.querySelectorAll('select.search-select').forEach(select => {
            if (select.dataset.nativeSearchReady === '1') return;
            select.dataset.nativeSearchReady = '1';

            const wrap = document.createElement('div');
            wrap.className = 'item-search-wrap';

            const input = document.createElement('input');
            input.type = 'text';
            input.className = 'form-control form-control-sm item-search-input';
            input.placeholder = select.getAttribute('data-search-placeholder') || (select.classList.contains('item-select') ? 'Type item name, code or unit...' : 'Type to search...');
            input.autocomplete = 'off';

            const menu = document.createElement('div');
            const isInventoryItem = select.classList.contains('item-select');
            menu.className = 'item-search-menu' + (isInventoryItem ? ' inventory-item-picker' : '');

            select.parentNode.insertBefore(wrap, select);
            wrap.appendChild(input);
            wrap.appendChild(select);
            document.body.appendChild(menu);

            function positionMenu(){
                const rect = input.getBoundingClientRect();
                const margin = 12;

                // Inventory items use a large, fixed picker in the viewport.
                // This deliberately avoids every overflow/scroll container in the PO grid.
                if (isInventoryItem) {
                    const width = Math.min(760, window.innerWidth - 32);
                    const top = Math.max(18, Math.min(90, Math.floor(window.innerHeight * 0.10)));
                    const height = Math.max(300, window.innerHeight - (top * 2));
                    menu.style.setProperty('left', '50%', 'important');
                    menu.style.setProperty('transform', 'translateX(-50%)', 'important');
                    menu.style.setProperty('top', top + 'px', 'important');
                    menu.style.setProperty('bottom', 'auto', 'important');
                    menu.style.setProperty('width', width + 'px', 'important');
                    menu.style.setProperty('height', height + 'px', 'important');
                    menu.style.setProperty('max-height', height + 'px', 'important');
                    menu.style.setProperty('z-index', '2147483647', 'important');
                    return;
                }

                const gap = 8;
                const below = window.innerHeight - rect.bottom - margin;
                const above = rect.top - margin;
                const openUp = below < 280 && above > below;
                const available = Math.max(180, (openUp ? above : below) - gap);
                const desiredHeight = Math.min(440, Math.floor(window.innerHeight * 0.55), available);
                const desiredWidth = Math.max(430, rect.width);
                let left = rect.left;
                if (left + desiredWidth > window.innerWidth - margin) left = window.innerWidth - desiredWidth - margin;
                left = Math.max(margin, left);

                menu.style.setProperty('transform', 'none', 'important');
                menu.style.setProperty('height', 'auto', 'important');
                menu.style.setProperty('left', left + 'px', 'important');
                menu.style.setProperty('width', Math.min(desiredWidth, window.innerWidth - (margin * 2)) + 'px', 'important');
                menu.style.setProperty('max-height', desiredHeight + 'px', 'important');
                menu.style.setProperty('z-index', '2147483647', 'important');

                if (openUp) {
                    menu.style.setProperty('top', 'auto', 'important');
                    menu.style.setProperty('bottom', (window.innerHeight - rect.top + gap) + 'px', 'important');
                } else {
                    menu.style.setProperty('bottom', 'auto', 'important');
                    menu.style.setProperty('top', (rect.bottom + gap) + 'px', 'important');
                }
            }

            function openMenu(){
                positionMenu();
                menu.classList.add('open');
                wrap.classList.add('open');
            }

            function closeMenu(){
                menu.classList.remove('open');
                wrap.classList.remove('open');
            }

            const getOptions = () => Array.from(select.options).filter(opt => opt.value !== '');

            function optionSubText(opt){
                const explicit = opt.getAttribute('data-subtext') || '';
                if (explicit.trim() !== '') return explicit.trim();
                const cost = opt.getAttribute('data-cost') || '0';
                const tax = opt.getAttribute('data-tax') || '0';
                const parts = [];
                if (Number(cost) > 0) parts.push('Cost: ' + Number(cost).toFixed(4));
                if (Number(tax) > 0) parts.push('Tax: ' + Number(tax).toFixed(2) + '%');
                return parts.join(' · ');
            }

            function render(term){
                const q = String(term || '').trim().toLowerCase();
                const matches = getOptions().filter(opt => (opt.textContent + ' ' + (opt.getAttribute('data-subtext') || '')).toLowerCase().includes(q)).slice(0, 500);
                menu.innerHTML = '';

                if (isInventoryItem) {
                    const pickerHead = document.createElement('div');
                    pickerHead.className = 'inventory-picker-head';
                    const pickerTitle = document.createElement('div');
                    pickerTitle.innerHTML = '<strong>Select Inventory Item</strong><span>' + matches.length + ' matching item' + (matches.length === 1 ? '' : 's') + '</span>';
                    const pickerClose = document.createElement('button');
                    pickerClose.type = 'button';
                    pickerClose.className = 'inventory-picker-close';
                    pickerClose.setAttribute('aria-label', 'Close item picker');
                    pickerClose.innerHTML = '&times;';
                    pickerClose.addEventListener('mousedown', function(e){ e.preventDefault(); closeMenu(); });
                    pickerHead.appendChild(pickerTitle);
                    pickerHead.appendChild(pickerClose);
                    menu.appendChild(pickerHead);
                }

                if (!matches.length) {
                    const empty = document.createElement('div');
                    empty.className = 'item-search-empty';
                    empty.textContent = 'No matching items found';
                    menu.appendChild(empty);
                    return;
                }

                matches.forEach((opt, idx) => {
                    const item = document.createElement('div');
                    item.className = 'item-search-option' + (idx === 0 ? ' active' : '');
                    item.dataset.value = opt.value;

                    const title = document.createElement('div');
                    title.textContent = opt.textContent.trim();
                    item.appendChild(title);

                    const sub = optionSubText(opt);
                    if (sub) {
                        const muted = document.createElement('span');
                        muted.className = 'muted';
                        muted.textContent = sub;
                        item.appendChild(muted);
                    }

                    item.addEventListener('mousedown', function(e){
                        e.preventDefault();
                        select.value = opt.value;
                        input.value = opt.textContent.trim();
                        closeMenu();
                        select.dispatchEvent(new Event('change', {bubbles:true}));
                    });
                    menu.appendChild(item);
                });
            }

            input.addEventListener('focus', function(){ render(input.value); openMenu(); input.select(); });
            input.addEventListener('click', function(){ render(input.value); openMenu(); });
            input.addEventListener('input', function(){ select.value = ''; render(input.value); openMenu(); if (select.classList.contains('item-select')) recalc(); });
            input.addEventListener('keydown', function(e){
                const options = Array.from(menu.querySelectorAll('.item-search-option'));
                if (!options.length) return;
                let activeIndex = options.findIndex(o => o.classList.contains('active'));
                if (e.key === 'ArrowDown') {
                    e.preventDefault();
                    options[activeIndex]?.classList.remove('active');
                    activeIndex = activeIndex >= options.length - 1 ? 0 : activeIndex + 1;
                    options[activeIndex].classList.add('active');
                    options[activeIndex].scrollIntoView({block:'nearest'});
                } else if (e.key === 'ArrowUp') {
                    e.preventDefault();
                    options[activeIndex]?.classList.remove('active');
                    activeIndex = activeIndex <= 0 ? options.length - 1 : activeIndex - 1;
                    options[activeIndex].classList.add('active');
                    options[activeIndex].scrollIntoView({block:'nearest'});
                } else if (e.key === 'Enter') {
                    e.preventDefault();
                    (options[activeIndex] || options[0]).dispatchEvent(new MouseEvent('mousedown', {bubbles:true}));
                } else if (e.key === 'Escape') {
                    closeMenu();
                }
            });

            document.addEventListener('mousedown', function(e){
                if (!wrap.contains(e.target) && !menu.contains(e.target)) closeMenu();
            });
            window.addEventListener('resize', function(){ if (menu.classList.contains('open')) positionMenu(); });
            document.addEventListener('scroll', function(){ if (menu.classList.contains('open')) positionMenu(); }, true);

            if (select.value) {
                const selected = select.options[select.selectedIndex];
                input.value = selected ? selected.textContent.trim() : '';
            }
        });
    }

    function recalc(){
        let subtotal = 0, tax = 0;
        lineBox.querySelectorAll('.po-line').forEach(line => {
            const qtyInput = line.querySelector('.qty-input');
            let qty = parseFloat(qtyInput.value || '0');
            if (!Number.isNaN(qty)) qty = Math.round(qty);
            const cost = parseFloat(line.querySelector('.cost-input').value || '0');
            const taxSelect = line.querySelector('.tax-select');
            const modeSelect = line.querySelector('.price-tax-mode');
            const taxOption = taxSelect ? taxSelect.options[taxSelect.selectedIndex] : null;
            const taxRate = parseFloat(taxOption ? (taxOption.getAttribute('data-rate') || '0') : '0');
            const taxType = taxOption ? (taxOption.getAttribute('data-type') || 'Percentage') : 'Percentage';
            const priceTaxMode = modeSelect ? modeSelect.value : 'exclusive';
            const amountEl = line.querySelector('.amount-input');
            const amountRaw = amountEl ? amountEl.value : '';
            /* Entered Amount is authoritative when present; otherwise qty x price as before. */
            const grossInput = amountRaw !== '' ? (parseFloat(amountRaw) || 0) : qty * cost;
            let net = grossInput;
            let lineTax = 0;

            if (taxRate > 0) {
                if (priceTaxMode === 'inclusive') {
                    if (taxType === 'Fixed') {
                        lineTax = taxRate * Math.max(1, qty);
                        net = Math.max(0, grossInput - lineTax);
                    } else {
                        lineTax = grossInput * (taxRate / (100 + taxRate));
                        net = grossInput - lineTax;
                    }
                } else {
                    net = grossInput;
                    lineTax = taxType === 'Fixed' ? taxRate * Math.max(1, qty) : net * (taxRate / 100);
                }
            }

            subtotal += net;
            tax += lineTax;
            const label = line.querySelector('.line-total');
            if (label) {
                const unitNet = qty > 0 ? net / qty : 0;
                label.textContent = 'Net: ' + money(net) + ' | VAT: ' + money(lineTax) + ' | Total: ' + money(net + lineTax) + ' | Stock cost: ' + unitNet.toFixed(4);
            }
        });
        subtotalLabel.textContent = money(subtotal);
        taxLabel.textContent = money(tax);
        totalLabel.textContent = money(subtotal + tax);
        const rows=Array.from(lineBox.querySelectorAll('.po-line')); rows.forEach((r,i)=>{const n=r.querySelector('.po-line-index'); if(n)n.textContent=String(i+1);}); if (lineCount) lineCount.textContent = rows.length;
    }

    function addLine(){
        const fragment = template.content.cloneNode(true);
        lineBox.appendChild(fragment);
        const newLine = lineBox.lastElementChild;
        initSearchSelect(newLine);
        recalc();

        /* Keep the newest row visible without changing the table layout. */
        requestAnimationFrame(function () {
            lineBox.scrollTop = lineBox.scrollHeight;
        });
    }

    addLineBtn.addEventListener('click', addLine);

    /* Bidirectional Amount <-> Unit Price sync (same behaviour as grn.php):
       type the AMOUNT off the quote/invoice -> unit price back-calculates at
       6dp; type qty or unit price -> amount fills as qty x price. */
    function syncAmountFromPrice(line){
        const amountEl = line.querySelector('.amount-input');
        if (!amountEl) return;
        const qty = parseFloat((line.querySelector('.qty-input') || {}).value || '0') || 0;
        const cost = parseFloat((line.querySelector('.cost-input') || {}).value || '0') || 0;
        amountEl.value = (qty * cost).toFixed(2);
    }
    lineBox.addEventListener('input', function(e){
        const line = e.target.closest('.po-line');
        if (line) {
            if (e.target.classList.contains('amount-input')) {
                const qty = parseFloat((line.querySelector('.qty-input') || {}).value || '0') || 0;
                const amount = parseFloat(e.target.value || '0') || 0;
                const costEl = line.querySelector('.cost-input');
                if (costEl && qty > 0) costEl.value = (amount / qty).toFixed(6);
            } else if (e.target.classList.contains('qty-input') || e.target.classList.contains('cost-input')) {
                syncAmountFromPrice(line);
            }
        }
        recalc();
    });
    lineBox.addEventListener('change', function(e){
        if (e.target.classList.contains('item-select')) {
            const opt = e.target.options[e.target.selectedIndex];
            const line = e.target.closest('.po-line');
            const cost = opt ? opt.getAttribute('data-cost') : '0';
            const costInput = line.querySelector('.cost-input');
            if (costInput && (!costInput.value || parseFloat(costInput.value) <= 0)) costInput.value = cost || '0';
            syncAmountFromPrice(line);
            recalc();
        }
    });
    lineBox.addEventListener('click', function(e){
        const btn = e.target.closest('.remove-line');
        if (btn) {
            btn.closest('.po-line').remove();
            recalc();
        }
    });
    initSearchSelect(document);

    document.getElementById('poForm').addEventListener('submit', function(e){
        const supplierSelect = this.querySelector('select[name="supplier_id"]');
        if (supplierSelect && !supplierSelect.value) {
            e.preventDefault();
            alert('Please select supplier.');
            const supplierSearch = supplierSelect.closest('.item-search-wrap')?.querySelector('.item-search-input');
            if (supplierSearch) supplierSearch.focus();
            return;
        }
        if (!lineBox.querySelector('.po-line')) {
            e.preventDefault();
            alert('Please add at least one PO line.');
        }
    });
    const editLines = <?php echo json_encode($editLines, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT); ?>;
    function addLineWithData(data){
        addLine();
        const line = lineBox.lastElementChild;
        if (!data) return;
        const itemSel=line.querySelector('.item-select'); itemSel.value=String(data.item_id||''); itemSel.dispatchEvent(new Event('change',{bubbles:true}));
        line.querySelector('.qty-input').value=parseFloat(data.qty_ordered||1);
        line.querySelector('.cost-input').value=parseFloat(data.unit_price_entered||data.unit_cost||0).toFixed(4);
        line.querySelector('.amount-input').value=parseFloat((data.price_tax_mode==='inclusive' ? data.line_total : (parseFloat(data.line_total||0)-parseFloat(data.line_tax||0)))||0).toFixed(2);
        line.querySelector('.price-tax-mode').value=data.price_tax_mode||'exclusive';
        line.querySelector('.tax-select').value=data.tax_id||'';
        const searchInput=line.querySelector('.item-search-input'); const opt=itemSel.options[itemSel.selectedIndex]; if(searchInput&&opt) searchInput.value=opt.textContent.trim();
        syncAmountFromPrice(line); recalc();
    }
    if (editLines.length) editLines.forEach(addLineWithData); else addLine();

    const poModalEl=document.getElementById('poModal');
    const poModal=poModalEl ? bootstrap.Modal.getOrCreateInstance(poModalEl) : null;
    document.getElementById('openPoModal')?.addEventListener('click',()=>poModal?.show());
    document.getElementById('clearPoLines')?.addEventListener('click',()=>{ if(confirm('Clear all purchase order lines?')){ lineBox.innerHTML=''; addLine(); } });
    document.getElementById('poGlobalItemSearch')?.addEventListener('focus',()=>{ const input=lineBox.querySelector('.item-search-input'); if(input){input.focus();input.select();} });
    document.getElementById('poGlobalItemSearch')?.addEventListener('input',function(){ const input=lineBox.querySelector('.item-search-input'); if(input){input.value=this.value;input.dispatchEvent(new Event('input',{bubbles:true}));} });
    <?php if ($editPo): ?>poModal?.show();<?php endif; ?>

    const quickEl=document.getElementById('quickItemModal');
    const quickModal=quickEl ? bootstrap.Modal.getOrCreateInstance(quickEl) : null;
    document.getElementById('openQuickItem')?.addEventListener('click',()=>quickModal?.show());
    document.getElementById('quickItemForm')?.addEventListener('submit', async function(e){
        e.preventDefault(); const err=document.getElementById('quickItemError'); err.classList.add('d-none');
        const fd=new FormData(this); fd.append('action','quick_add_item');
        const csrf=document.getElementById('poForm')?.querySelector('input[name="csrf_token"]'); if(csrf) fd.append('csrf_token',csrf.value);
        try{
            const res=await fetch('purchase_orders.php',{method:'POST',body:fd,headers:{'X-Requested-With':'XMLHttpRequest'}});
            const data=await res.json(); if(!res.ok||!data.ok) throw new Error(data.message||'Could not add item.');
            document.querySelectorAll('select.item-select').forEach(sel=>{const o=document.createElement('option');o.value=data.item.id;o.dataset.cost=data.item.cost;o.dataset.tax=data.item.tax;o.textContent=data.item.name+(data.item.code?' - '+data.item.code:'');sel.appendChild(o);});
            addLine(); const line=lineBox.lastElementChild; const sel=line.querySelector('.item-select'); sel.value=String(data.item.id); sel.dispatchEvent(new Event('change',{bubbles:true})); const input=line.querySelector('.item-search-input'); if(input) input.value=data.item.name+(data.item.code?' - '+data.item.code:'');
            quickModal.hide(); this.reset();
        }catch(ex){err.textContent=ex.message;err.classList.remove('d-none');}
    });
});
</script>

<script>
/* Receive Into GRN: Actual Unit Price <-> Amount sync.
   - Type the AMOUNT off the delivery invoice -> actual unit price
     back-calculates (amount / qty, 6dp), same as grn.php.
   - Change qty or price -> amount refreshes, but only if an amount was
     already entered; a blank Amount means "price-driven" server-side. */
document.addEventListener('DOMContentLoaded', function(){
    const receiveTable = document.getElementById('receiveGrnTable');
    if (!receiveTable) return;

    const subtotalEl = document.getElementById('receiveSummarySubtotal');
    const taxEl = document.getElementById('receiveSummaryTax');
    const totalEl = document.getElementById('receiveSummaryTotal');

    function receiveMoney(value) {
        return (Number(value) || 0).toLocaleString(undefined, {
            minimumFractionDigits: 2,
            maximumFractionDigits: 2
        });
    }

    function recalcReceiveSummary() {
        let subtotal = 0;
        let taxTotal = 0;

        receiveTable.querySelectorAll('tr.receive-line').forEach(function(row) {
            const qtyEl = row.querySelector('.receive-qty');
            const priceEl = row.querySelector('.receive-price');
            const amountEl = row.querySelector('.receive-amount');

            const qty = parseFloat((qtyEl && qtyEl.value) || '0') || 0;
            const price = parseFloat((priceEl && priceEl.value) || '0') || 0;
            const enteredAmount = amountEl && amountEl.value !== ''
                ? (parseFloat(amountEl.value) || 0)
                : null;

            if (qty <= 0) return;

            const grossInput = enteredAmount !== null ? enteredAmount : qty * price;
            const taxRate = parseFloat(row.dataset.taxRate || '0') || 0;
            const taxType = row.dataset.taxType === 'Fixed' ? 'Fixed' : 'Percentage';
            const taxMode = row.dataset.taxMode === 'inclusive' ? 'inclusive' : 'exclusive';

            let net = grossInput;
            let lineTax = 0;

            if (taxRate > 0) {
                if (taxMode === 'inclusive') {
                    if (taxType === 'Fixed') {
                        lineTax = taxRate * Math.max(1, qty);
                        net = Math.max(0, grossInput - lineTax);
                    } else {
                        lineTax = grossInput * (taxRate / (100 + taxRate));
                        net = grossInput - lineTax;
                    }
                } else {
                    net = grossInput;
                    lineTax = taxType === 'Fixed'
                        ? taxRate * Math.max(1, qty)
                        : net * (taxRate / 100);
                }
            }

            subtotal += net;
            taxTotal += lineTax;
        });

        if (subtotalEl) subtotalEl.textContent = receiveMoney(subtotal);
        if (taxEl) taxEl.textContent = receiveMoney(taxTotal);
        if (totalEl) totalEl.textContent = receiveMoney(subtotal + taxTotal);
    }

    receiveTable.addEventListener('input', function(e){
        const row = e.target.closest('tr.receive-line');
        if (!row) return;

        const qtyEl = row.querySelector('.receive-qty');
        const priceEl = row.querySelector('.receive-price');
        const amountEl = row.querySelector('.receive-amount');
        const qty = parseFloat((qtyEl && qtyEl.value) || '0') || 0;

        if (amountEl && e.target === amountEl) {
            const amount = parseFloat(amountEl.value || '0') || 0;
            if (priceEl && qty > 0) priceEl.value = (amount / qty).toFixed(6);
        } else if (e.target === qtyEl || e.target === priceEl) {
            if (amountEl && amountEl.value !== '') {
                const price = parseFloat((priceEl && priceEl.value) || '0') || 0;
                amountEl.value = (qty * price).toFixed(2);
            }
        }

        recalcReceiveSummary();
    });

    receiveTable.addEventListener('change', recalcReceiveSummary);
    recalcReceiveSummary();
});
</script>

<?php require_once __DIR__ . '/../../includes/footer.php'; ?>
