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

$pageTitle = 'Stock Movements';

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('sm_table_exists')) {
    function sm_table_exists(PDO $pdo, string $tableName): bool {
        $stmt = $pdo->prepare("
            SELECT COUNT(*)
            FROM information_schema.tables
            WHERE table_schema = DATABASE()
              AND table_name = :table_name
        ");
        $stmt->execute([':table_name' => $tableName]);
        return (int)$stmt->fetchColumn() > 0;
    }
}
if (!function_exists('sm_column_exists')) {
    function sm_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('sm_flash')) {
    function sm_flash(string $type, string $message): void {
        $_SESSION['stock_movements_flash'][] = ['type' => $type, 'message' => $message];
    }
}
if (!function_exists('sm_get_flash')) {
    function sm_get_flash(): array {
        $items = $_SESSION['stock_movements_flash'] ?? [];
        unset($_SESSION['stock_movements_flash']);
        return $items;
    }
}
if (!function_exists('sm_stock_balance')) {
    function sm_stock_balance(PDO $pdo, int $itemId, int $storeId): float {
        $stmt = $pdo->prepare("
            SELECT COALESCE(SUM(qty_in - qty_out),0)
            FROM stock_movements
            WHERE item_id = :item_id
              AND store_id = :store_id
        ");
        $stmt->execute([':item_id' => $itemId, ':store_id' => $storeId]);
        return (float)$stmt->fetchColumn();
    }
}
if (!function_exists('sm_recalculate_avg_cost')) {
    function sm_recalculate_avg_cost(PDO $pdo, int $itemId): void {
        if (!sm_table_exists($pdo, 'inventory_items')) return;

        $stmt = $pdo->prepare("
            SELECT
                COALESCE(SUM(qty_in),0) AS total_in_qty,
                COALESCE(SUM(qty_in * unit_cost),0) AS total_in_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['total_in_qty'] ?? 0);
        $cost = (float)($row['total_in_cost'] ?? 0);

        if ($qty > 0 && sm_column_exists($pdo, 'inventory_items', 'avg_cost')) {
            $avg = $cost / $qty;
            $stmt = $pdo->prepare("UPDATE inventory_items SET avg_cost = :avg_cost WHERE id = :id");
            $stmt->execute([':avg_cost' => $avg, ':id' => $itemId]);
        }
    }
}
if (!function_exists('sm_next_batch_no')) {
    function sm_next_batch_no(): string {
        return 'SM-' . date('Ymd-His') . '-' . strtoupper(substr(bin2hex(random_bytes(3)), 0, 6));
    }
}

if (!function_exists('sm_get_item_cost')) {
    function sm_get_item_cost(PDO $pdo, int $itemId): float {
        $stmt = $pdo->prepare("SELECT avg_cost, cost_price FROM inventory_items WHERE id = :id LIMIT 1");
        $stmt->execute([':id' => $itemId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
        return (float)(($row['avg_cost'] ?? 0) ?: ($row['cost_price'] ?? 0));
    }
}
if (!function_exists('sm_find_conversion_for_destination')) {
    function sm_find_conversion_for_destination(PDO $pdo, int $destinationItemId): ?array {
        if (!sm_table_exists($pdo, 'inventory_item_conversions')) {
            return null;
        }

        $stmt = $pdo->prepare("
            SELECT
                c.*,
                src.item_name AS source_item_name,
                src.item_code AS source_item_code,
                dst.item_name AS destination_item_name,
                dst.item_code AS destination_item_code
            FROM inventory_item_conversions c
            INNER JOIN inventory_items src ON src.id = c.source_item_id
            INNER JOIN inventory_items dst ON dst.id = c.destination_item_id
            WHERE c.destination_item_id = :destination_item_id
              AND c.is_active = 1
            ORDER BY c.id ASC
            LIMIT 1
        ");
        $stmt->execute([':destination_item_id' => $destinationItemId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return $row ?: null;
    }
}
if (!function_exists('sm_calculate_conversion_qty')) {
    function sm_calculate_conversion_qty(array $conversion, float $destinationQty): array {
        $sourceQtyRule = (float)($conversion['source_qty'] ?? 1);
        $destinationQtyRule = (float)($conversion['destination_qty'] ?? 1);

        if ($sourceQtyRule <= 0 || $destinationQtyRule <= 0) {
            throw new RuntimeException('Invalid item conversion setup. Source and destination quantities must be greater than zero.');
        }

        $factor = $destinationQtyRule / $sourceQtyRule;
        $sourceIssueQty = $destinationQty / $factor;
        $destinationReceiveQty = $destinationQty;

        $allowFractional = (int)($conversion['allow_fractional_source'] ?? 0) === 1;
        $roundUp = (int)($conversion['round_source_up'] ?? 0) === 1;

        if (!$allowFractional) {
            if ($roundUp) {
                $sourceIssueQty = ceil($sourceIssueQty - 0.0000001);
                $destinationReceiveQty = $sourceIssueQty * $factor;
            } else {
                $rounded = round($sourceIssueQty);
                if (abs($sourceIssueQty - $rounded) > 0.0001) {
                    throw new RuntimeException(
                        'Converted item quantity must be a multiple of ' . number_format($destinationQtyRule, 4) .
                        '. Conversion: ' . (($conversion['conversion_name'] ?? '') ?: 'source item to destination item')
                    );
                }
                $sourceIssueQty = $rounded;
            }
        }

        return [
            'factor' => $factor,
            'source_issue_qty' => $sourceIssueQty,
            'destination_receive_qty' => $destinationReceiveQty,
        ];
    }
}
if (!function_exists('sm_destination_label')) {
    function sm_destination_label(array $row): string {
        $type = strtoupper((string)($row['destination_type'] ?? ''));
        $store = trim((string)($row['destination_store_name'] ?? ''));
        $room = trim((string)($row['destination_room_label'] ?? ''));
        $name = trim((string)($row['destination_name'] ?? ''));

        if ($type === 'STORE' && $store !== '') return 'Store: ' . $store;
        if ($type === 'ROOM' && $room !== '') return 'Room: ' . $room;
        if ($type !== '' && $name !== '') return ucfirst(strtolower($type)) . ': ' . $name;
        if ($name !== '') return $name;
        if ($store !== '') return 'Store: ' . $store;
        return '—';
    }
}

$errors = [];

try {
    $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),
        INDEX idx_store_location_active (is_active)
    ) 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 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),
        INDEX idx_inventory_item_name (item_name),
        INDEX idx_inventory_item_active (is_active)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS stock_movements (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        batch_no VARCHAR(40) NULL,
        line_no INT UNSIGNED NOT NULL DEFAULT 1,
        item_id INT UNSIGNED NOT NULL,
        store_id INT UNSIGNED NOT NULL,
        destination_type VARCHAR(30) NULL,
        destination_store_id INT UNSIGNED NULL,
        destination_room_id INT UNSIGNED NULL,
        destination_name VARCHAR(180) 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_batch (batch_no),
        INDEX idx_stock_item_store (item_id, store_id),
        INDEX idx_stock_movement_date (movement_date),
        INDEX idx_stock_reference (reference_type, reference_id),
        INDEX idx_stock_destination (destination_type, destination_store_id, destination_room_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS inventory_item_conversions (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        source_item_id INT UNSIGNED NOT NULL,
        destination_item_id INT UNSIGNED NOT NULL,
        source_qty DECIMAL(14,4) NOT NULL DEFAULT 1.0000,
        destination_qty DECIMAL(14,4) NOT NULL DEFAULT 1.0000,
        allow_fractional_source TINYINT(1) NOT NULL DEFAULT 0,
        round_source_up TINYINT(1) NOT NULL DEFAULT 0,
        conversion_name VARCHAR(180) 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_item_conversion (source_item_id, destination_item_id),
        INDEX idx_conversion_source (source_item_id),
        INDEX idx_conversion_destination (destination_item_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $stmtUnitSeed = $pdo->prepare("INSERT IGNORE INTO inventory_units (unit_code, unit_name) VALUES (:code, :name)");
    foreach ([['TOT','Tot / Shot'],['SERVE','Serving'],['GLASS','Glass']] as $u) {
        $stmtUnitSeed->execute([':code' => $u[0], ':name' => $u[1]]);
    }

    $alterCols = [
        'batch_no' => "ALTER TABLE stock_movements ADD COLUMN batch_no VARCHAR(40) NULL AFTER id",
        'line_no' => "ALTER TABLE stock_movements ADD COLUMN line_no INT UNSIGNED NOT NULL DEFAULT 1 AFTER batch_no",
        'destination_type' => "ALTER TABLE stock_movements ADD COLUMN destination_type VARCHAR(30) NULL AFTER store_id",
        'destination_store_id' => "ALTER TABLE stock_movements ADD COLUMN destination_store_id INT UNSIGNED NULL AFTER destination_type",
        'destination_room_id' => "ALTER TABLE stock_movements ADD COLUMN destination_room_id INT UNSIGNED NULL AFTER destination_store_id",
        'destination_name' => "ALTER TABLE stock_movements ADD COLUMN destination_name VARCHAR(180) NULL AFTER destination_room_id",
        'conversion_id' => "ALTER TABLE stock_movements ADD COLUMN conversion_id INT UNSIGNED NULL AFTER destination_name",
        'conversion_label' => "ALTER TABLE stock_movements ADD COLUMN conversion_label VARCHAR(180) NULL AFTER conversion_id",
        'converted_from_item_id' => "ALTER TABLE stock_movements ADD COLUMN converted_from_item_id INT UNSIGNED NULL AFTER conversion_label",
        'converted_to_item_id' => "ALTER TABLE stock_movements ADD COLUMN converted_to_item_id INT UNSIGNED NULL AFTER converted_from_item_id",
    ];
    foreach ($alterCols as $col => $sql) {
        if (!sm_column_exists($pdo, 'stock_movements', $col)) $pdo->exec($sql);
    }
} catch (Throwable $e) {
    $errors[] = 'Could not prepare stock movement tables: ' . $e->getMessage();
}

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

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

        if ($action === 'save_movement') {
            $movementType = (string)($_POST['movement_type'] ?? '');
            $storeId = (int)($_POST['store_id'] ?? 0);
            $toStoreId = (int)($_POST['to_store_id'] ?? 0);
            $destinationType = strtoupper(trim((string)($_POST['destination_type'] ?? '')));
            $destinationRoomId = (int)($_POST['destination_room_id'] ?? 0);
            $destinationName = trim((string)($_POST['destination_name'] ?? ''));
            $movementDate = trim((string)($_POST['movement_date'] ?? date('Y-m-d H:i:s')));
            $referenceType = trim((string)($_POST['reference_type'] ?? 'Manual'));
            $referenceId = (int)($_POST['reference_id'] ?? 0);
            $notes = trim((string)($_POST['notes'] ?? ''));

            $itemIds = $_POST['item_id'] ?? [];
            $qtys = $_POST['qty'] ?? [];
            $unitCosts = $_POST['unit_cost'] ?? [];

            if (!is_array($itemIds)) $itemIds = [$itemIds];
            if (!is_array($qtys)) $qtys = [$qtys];
            if (!is_array($unitCosts)) $unitCosts = [$unitCosts];

            $allowed = ['OPENING','GRN','ISSUE','TRANSFER','ADJUSTMENT_IN','ADJUSTMENT_OUT','WASTAGE','RETURN'];
            $destinationTypes = ['STORE','ROOM','DEPARTMENT','STAFF','GUEST','SUPPLIER','OTHER'];

            if (!in_array($movementType, $allowed, true)) throw new RuntimeException('Invalid movement type selected.');
            if ($storeId <= 0) throw new RuntimeException('Please select the place of origin / source store.');
            if (strtotime($movementDate) === false) $movementDate = date('Y-m-d H:i:s');

            if ($movementType === 'TRANSFER') {
                $destinationType = 'STORE';
                if ($toStoreId <= 0) throw new RuntimeException('Please select destination store.');
                if ($toStoreId === $storeId) throw new RuntimeException('Source and destination store cannot be the same.');
            }

            if (in_array($movementType, ['ISSUE','ADJUSTMENT_OUT','WASTAGE'], true)) {
                if ($destinationType === '' || !in_array($destinationType, $destinationTypes, true)) {
                    throw new RuntimeException('Please select a destination type for the issue / stock out.');
                }
                if ($destinationType === 'STORE') {
                    if ($toStoreId <= 0) throw new RuntimeException('Please select destination store.');
                    if ($toStoreId === $storeId) throw new RuntimeException('Source and destination store cannot be the same.');
                } elseif ($destinationType === 'ROOM') {
                    if ($destinationRoomId <= 0 && $destinationName === '') {
                        throw new RuntimeException('Please select a room or enter room details for the destination.');
                    }
                } elseif ($destinationName === '') {
                    throw new RuntimeException('Please enter destination details.');
                }
            }

            $lines = [];
            foreach ($itemIds as $idx => $rawItemId) {
                $itemId = (int)$rawItemId;
                $qty = (float)($qtys[$idx] ?? 0);
                $unitCost = (float)($unitCosts[$idx] ?? 0);

                if ($itemId <= 0 && $qty <= 0) continue;
                if ($itemId <= 0) throw new RuntimeException('One movement line has no item selected.');
                if ($qty <= 0) throw new RuntimeException('Quantity must be greater than zero on every line.');

                $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('Inventory item not found on one line.');

                if ($unitCost <= 0) $unitCost = (float)($item['avg_cost'] ?: $item['cost_price']);
                $lines[] = ['item_id' => $itemId, 'qty' => $qty, 'unit_cost' => $unitCost];
            }

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

            $outTypes = ['ISSUE','ADJUSTMENT_OUT','WASTAGE','TRANSFER'];
            if (in_array($movementType, $outTypes, true)) {
                foreach ($lines as $line) {
                    $checkItemId = (int)$line['item_id'];
                    $checkQty = (float)$line['qty'];

                    if ($movementType === 'TRANSFER') {
                        $conversion = sm_find_conversion_for_destination($pdo, $checkItemId);
                        if ($conversion) {
                            $calc = sm_calculate_conversion_qty($conversion, $checkQty);
                            $checkItemId = (int)$conversion['source_item_id'];
                            $checkQty = (float)$calc['source_issue_qty'];
                        }
                    }

                    $balance = sm_stock_balance($pdo, $checkItemId, $storeId);
                    if ($balance + 0.0001 < $checkQty) {
                        throw new RuntimeException('Insufficient stock on one line. Required: ' . money_fmt($checkQty) . ', Available: ' . money_fmt($balance));
                    }
                }
            }

            $pdo->beginTransaction();

            $batchNo = sm_next_batch_no();
            $postedItemIds = [];

            $insert = $pdo->prepare("
                INSERT INTO stock_movements
                (batch_no, line_no, item_id, store_id, destination_type, destination_store_id, destination_room_id, destination_name,
                 conversion_id, conversion_label, converted_from_item_id, converted_to_item_id,
                 movement_type, qty_in, qty_out, unit_cost, total_cost, reference_type, reference_id, notes, movement_date)
                VALUES
                (:batch_no, :line_no, :item_id, :store_id, :destination_type, :destination_store_id, :destination_room_id, :destination_name,
                 :conversion_id, :conversion_label, :converted_from_item_id, :converted_to_item_id,
                 :movement_type, :qty_in, :qty_out, :unit_cost, :total_cost, :reference_type, :reference_id, :notes, :movement_date)
            ");

            $inTypes = ['OPENING','GRN','ADJUSTMENT_IN','RETURN'];
            $stockOutMap = [
                'ISSUE' => 'ISSUE',
                'ADJUSTMENT_OUT' => 'ADJUSTMENT_OUT',
                'WASTAGE' => 'WASTAGE',
            ];

            $lineNo = 1;
            foreach ($lines as $line) {
                $qty = (float)$line['qty'];
                $unitCost = (float)$line['unit_cost'];
                $totalCost = round($qty * $unitCost, 4);
                $itemId = (int)$line['item_id'];
                $postedItemIds[$itemId] = true;

                if ($movementType === 'TRANSFER') {
                    /*
                       Converted transfer support:
                       - If selected item is a destination item in inventory_item_conversions,
                         issue the source/bulk item from the source store and receive the
                         destination/outlet item into the destination store.
                       - Example: 1 Rum 1L Bottle OUT from Bar Bulk, 40 Rum Tots IN to Bar.
                       - If no conversion exists, the old same-item transfer remains unchanged.
                    */
                    $conversion = sm_find_conversion_for_destination($pdo, $itemId);

                    if ($conversion) {
                        $calc = sm_calculate_conversion_qty($conversion, $qty);

                        $sourceItemId = (int)$conversion['source_item_id'];
                        $destinationItemId = (int)$conversion['destination_item_id'];
                        $sourceIssueQty = (float)$calc['source_issue_qty'];
                        $destinationReceiveQty = (float)$calc['destination_receive_qty'];
                        $conversionFactor = (float)$calc['factor'];

                        $sourceUnitCost = sm_get_item_cost($pdo, $sourceItemId);
                        if ($sourceUnitCost <= 0) {
                            $sourceUnitCost = $unitCost;
                        }

                        $totalCost = round($sourceIssueQty * $sourceUnitCost, 4);
                        $destinationUnitCost = $destinationReceiveQty > 0 ? round($totalCost / $destinationReceiveQty, 6) : 0;

                        $conversionLabel = trim((string)($conversion['conversion_name'] ?? ''));
                        if ($conversionLabel === '') {
                            $conversionLabel = 'Converted transfer: ' . ($conversion['source_item_name'] ?? 'Source item') . ' to ' . ($conversion['destination_item_name'] ?? 'Destination item');
                        }

                        $postedItemIds[$sourceItemId] = true;
                        $postedItemIds[$destinationItemId] = true;

                        $insert->execute([
                            ':batch_no' => $batchNo,
                            ':line_no' => $lineNo,
                            ':item_id' => $sourceItemId,
                            ':store_id' => $storeId,
                            ':destination_type' => 'STORE',
                            ':destination_store_id' => $toStoreId,
                            ':destination_room_id' => null,
                            ':destination_name' => null,
                            ':conversion_id' => (int)$conversion['id'],
                            ':conversion_label' => $conversionLabel,
                            ':converted_from_item_id' => $sourceItemId,
                            ':converted_to_item_id' => $destinationItemId,
                            ':movement_type' => 'TRANSFER_OUT',
                            ':qty_in' => 0,
                            ':qty_out' => $sourceIssueQty,
                            ':unit_cost' => $sourceUnitCost,
                            ':total_cost' => $totalCost,
                            ':reference_type' => 'TRANSFER_CONVERSION',
                            ':reference_id' => null,
                            ':notes' => ($notes ?: 'Converted stock transfer out') . ' | ' . $conversionLabel . ' | Factor: 1 source = ' . money_fmt($conversionFactor) . ' destination',
                            ':movement_date' => date('Y-m-d H:i:s', strtotime($movementDate)),
                        ]);

                        $insert->execute([
                            ':batch_no' => $batchNo,
                            ':line_no' => $lineNo,
                            ':item_id' => $destinationItemId,
                            ':store_id' => $toStoreId,
                            ':destination_type' => 'STORE',
                            ':destination_store_id' => $storeId,
                            ':destination_room_id' => null,
                            ':destination_name' => null,
                            ':conversion_id' => (int)$conversion['id'],
                            ':conversion_label' => $conversionLabel,
                            ':converted_from_item_id' => $sourceItemId,
                            ':converted_to_item_id' => $destinationItemId,
                            ':movement_type' => 'TRANSFER_IN',
                            ':qty_in' => $destinationReceiveQty,
                            ':qty_out' => 0,
                            ':unit_cost' => $destinationUnitCost,
                            ':total_cost' => $totalCost,
                            ':reference_type' => 'TRANSFER_CONVERSION',
                            ':reference_id' => null,
                            ':notes' => ($notes ?: 'Converted stock transfer in') . ' | ' . $conversionLabel . ' | Source issued: ' . money_fmt($sourceIssueQty),
                            ':movement_date' => date('Y-m-d H:i:s', strtotime($movementDate)),
                        ]);
                    } else {
                        $insert->execute([
                            ':batch_no' => $batchNo,
                            ':line_no' => $lineNo,
                            ':item_id' => $itemId,
                            ':store_id' => $storeId,
                            ':destination_type' => 'STORE',
                            ':destination_store_id' => $toStoreId,
                            ':destination_room_id' => null,
                            ':destination_name' => null,
                            ':conversion_id' => null,
                            ':conversion_label' => null,
                            ':converted_from_item_id' => null,
                            ':converted_to_item_id' => null,
                            ':movement_type' => 'TRANSFER_OUT',
                            ':qty_in' => 0,
                            ':qty_out' => $qty,
                            ':unit_cost' => $unitCost,
                            ':total_cost' => $totalCost,
                            ':reference_type' => 'TRANSFER',
                            ':reference_id' => null,
                            ':notes' => $notes ?: 'Stock transfer out',
                            ':movement_date' => date('Y-m-d H:i:s', strtotime($movementDate)),
                        ]);

                        $insert->execute([
                            ':batch_no' => $batchNo,
                            ':line_no' => $lineNo,
                            ':item_id' => $itemId,
                            ':store_id' => $toStoreId,
                            ':destination_type' => 'STORE',
                            ':destination_store_id' => $storeId,
                            ':destination_room_id' => null,
                            ':destination_name' => null,
                            ':conversion_id' => null,
                            ':conversion_label' => null,
                            ':converted_from_item_id' => null,
                            ':converted_to_item_id' => null,
                            ':movement_type' => 'TRANSFER_IN',
                            ':qty_in' => $qty,
                            ':qty_out' => 0,
                            ':unit_cost' => $unitCost,
                            ':total_cost' => $totalCost,
                            ':reference_type' => 'TRANSFER',
                            ':reference_id' => null,
                            ':notes' => $notes ?: 'Stock transfer in',
                            ':movement_date' => date('Y-m-d H:i:s', strtotime($movementDate)),
                        ]);
                    }
                } else {
                    $qtyIn = in_array($movementType, $inTypes, true) ? $qty : 0;
                    $qtyOut = isset($stockOutMap[$movementType]) ? $qty : 0;

                    $insert->execute([
                        ':batch_no' => $batchNo,
                        ':line_no' => $lineNo,
                        ':item_id' => $itemId,
                        ':store_id' => $storeId,
                        ':destination_type' => $destinationType ?: null,
                        ':destination_store_id' => $destinationType === 'STORE' ? $toStoreId : null,
                        ':destination_room_id' => $destinationType === 'ROOM' && $destinationRoomId > 0 ? $destinationRoomId : null,
                        ':destination_name' => $destinationName !== '' ? $destinationName : null,
                        ':conversion_id' => null,
                        ':conversion_label' => null,
                        ':converted_from_item_id' => null,
                        ':converted_to_item_id' => null,
                        ':movement_type' => $movementType,
                        ':qty_in' => $qtyIn,
                        ':qty_out' => $qtyOut,
                        ':unit_cost' => $unitCost,
                        ':total_cost' => $totalCost,
                        ':reference_type' => $referenceType ?: 'Manual',
                        ':reference_id' => $referenceId > 0 ? $referenceId : null,
                        ':notes' => $notes ?: null,
                        ':movement_date' => date('Y-m-d H:i:s', strtotime($movementDate)),
                    ]);
                }

                $lineNo++;
            }

            foreach (array_keys($postedItemIds) as $itemId) {
                sm_recalculate_avg_cost($pdo, (int)$itemId);
            }

            $pdo->commit();

            sm_flash('success', 'Stock movement posted successfully. Batch: ' . $batchNo . ' with ' . count($lines) . ' product line(s).');
            header('Location: stock_movements.php?store_id=' . $storeId);
            exit;
        }

        if ($action === 'delete_movement') {
            $id = (int)($_POST['id'] ?? 0);
            if ($id <= 0) throw new RuntimeException('Invalid movement selected.');

            $stmt = $pdo->prepare("SELECT item_id, movement_type, reference_type FROM stock_movements WHERE id = :id LIMIT 1");
            $stmt->execute([':id' => $id]);
            $movement = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$movement) throw new RuntimeException('Movement not found.');
            if (in_array($movement['reference_type'], ['POS','POS_VOID'], true)) {
                throw new RuntimeException('POS movements cannot be deleted here. Void the POS receipt instead.');
            }

            $stmt = $pdo->prepare("DELETE FROM stock_movements WHERE id = :id");
            $stmt->execute([':id' => $id]);

            sm_recalculate_avg_cost($pdo, (int)$movement['item_id']);

            sm_flash('success', 'Stock movement line deleted.');
            header('Location: stock_movements.php');
            exit;
        }

        if ($action === 'delete_batch') {
            $batchNo = trim((string)($_POST['batch_no'] ?? ''));
            if ($batchNo === '') throw new RuntimeException('Invalid batch selected.');

            $stmt = $pdo->prepare("
                SELECT DISTINCT item_id, reference_type
                FROM stock_movements
                WHERE batch_no = :batch_no
            ");
            $stmt->execute([':batch_no' => $batchNo]);
            $batchRows = $stmt->fetchAll(PDO::FETCH_ASSOC);

            if (!$batchRows) throw new RuntimeException('Batch not found.');
            foreach ($batchRows as $batchRow) {
                if (in_array((string)$batchRow['reference_type'], ['POS','POS_VOID'], true)) {
                    throw new RuntimeException('POS movement batches cannot be deleted here. Void the POS receipt instead.');
                }
            }

            $pdo->beginTransaction();

            $stmt = $pdo->prepare("DELETE FROM stock_movements WHERE batch_no = :batch_no");
            $stmt->execute([':batch_no' => $batchNo]);

            $recalcIds = [];
            foreach ($batchRows as $batchRow) {
                $recalcIds[(int)$batchRow['item_id']] = true;
            }
            foreach (array_keys($recalcIds) as $itemId) {
                sm_recalculate_avg_cost($pdo, (int)$itemId);
            }

            $pdo->commit();

            sm_flash('success', 'Stock movement batch deleted successfully.');
            header('Location: stock_movements.php');
            exit;
        }

    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        sm_flash('danger', $e->getMessage());
        header('Location: stock_movements.php');
        exit;
    }
}

$stores = [];
$items = [];
$categories = [];
$rooms = [];

try {
    $stores = $pdo->query("SELECT * FROM store_locations WHERE is_active=1 ORDER BY location_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);
    $categories = $pdo->query("SELECT * FROM inventory_item_categories WHERE is_active=1 ORDER BY category_name ASC")->fetchAll(PDO::FETCH_ASSOC);

    if (sm_table_exists($pdo, 'rooms')) {
        $labelSql = sm_column_exists($pdo, 'rooms', 'room_no') ? 'room_no' : (sm_column_exists($pdo, 'rooms', 'room_number') ? 'room_number' : 'id');
        $rooms = $pdo->query("SELECT id, {$labelSql} AS room_label FROM rooms ORDER BY {$labelSql} ASC LIMIT 500")->fetchAll(PDO::FETCH_ASSOC);
    }
} catch (Throwable $e) {
    $errors[] = 'Could not load stock form data: ' . $e->getMessage();
}

$stockAvailabilityByStore = [];
try {
    if (sm_table_exists($pdo, 'stock_movements')) {
        $stmt = $pdo->query("
            SELECT
                sm.store_id,
                sm.item_id,
                COALESCE(SUM(sm.qty_in - sm.qty_out),0) AS balance_qty
            FROM stock_movements sm
            INNER JOIN inventory_items ii ON ii.id = sm.item_id
            WHERE ii.is_active = 1
              AND ii.is_stock_item = 1
            GROUP BY sm.store_id, sm.item_id
        ");
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $stockRow) {
            $sid = (int)$stockRow['store_id'];
            $iid = (int)$stockRow['item_id'];
            $stockAvailabilityByStore[$sid][$iid] = (float)$stockRow['balance_qty'];
        }
    }
} catch (Throwable $e) {
    // Do not block the page if live availability cannot be preloaded. Server-side stock validation still runs on save.
}

$conversionRulesForJs = [];
try {
    if (sm_table_exists($pdo, 'inventory_item_conversions')) {
        $stmt = $pdo->query("
            SELECT
                c.id,
                c.source_item_id,
                c.destination_item_id,
                c.source_qty,
                c.destination_qty,
                c.allow_fractional_source,
                c.round_source_up,
                c.conversion_name,
                src.item_name AS source_item_name,
                src.item_code AS source_item_code,
                su.unit_code AS source_unit_code,
                dst.item_name AS destination_item_name,
                dst.item_code AS destination_item_code,
                du.unit_code AS destination_unit_code
            FROM inventory_item_conversions c
            INNER JOIN inventory_items src ON src.id = c.source_item_id
            INNER JOIN inventory_items dst ON dst.id = c.destination_item_id
            LEFT JOIN inventory_units su ON su.id = src.unit_id
            LEFT JOIN inventory_units du ON du.id = dst.unit_id
            WHERE c.is_active = 1
            ORDER BY c.id ASC
        ");
        $conversionRulesForJs = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
} catch (Throwable $e) {
    $conversionRulesForJs = [];
}

$dateFrom = trim((string)($_GET['date_from'] ?? date('Y-m-01')));
$dateTo = trim((string)($_GET['date_to'] ?? date('Y-m-d')));
$filterStore = (int)($_GET['store_id'] ?? 0);
$filterItem = (int)($_GET['item_id'] ?? 0);
$filterType = trim((string)($_GET['movement_type'] ?? ''));
$search = trim((string)($_GET['q'] ?? ''));

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

$where = "DATE(sm.movement_date) BETWEEN :date_from AND :date_to";
$params = [
    ':date_from' => $dateFrom,
    ':date_to' => $dateTo,
];

if ($filterStore > 0) {
    $where .= " AND sm.store_id = :store_id";
    $params[':store_id'] = $filterStore;
}
if ($filterItem > 0) {
    $where .= " AND sm.item_id = :item_id";
    $params[':item_id'] = $filterItem;
}
if ($filterType !== '') {
    $where .= " AND sm.movement_type = :movement_type";
    $params[':movement_type'] = $filterType;
}
if ($search !== '') {
    $where .= " AND (
        ii.item_name LIKE :q_item_name
        OR ii.item_code LIKE :q_item_code
        OR sl.location_name LIKE :q_store_name
        OR dsl.location_name LIKE :q_dest_store_name
        OR sm.destination_name LIKE :q_destination_name
        OR sm.batch_no LIKE :q_batch_no
        OR sm.notes LIKE :q_notes
        OR sm.reference_type LIKE :q_reference_type
    )";

    $likeSearch = '%' . $search . '%';
    $params[':q_item_name'] = $likeSearch;
    $params[':q_item_code'] = $likeSearch;
    $params[':q_store_name'] = $likeSearch;
    $params[':q_dest_store_name'] = $likeSearch;
    $params[':q_destination_name'] = $likeSearch;
    $params[':q_batch_no'] = $likeSearch;
    $params[':q_notes'] = $likeSearch;
    $params[':q_reference_type'] = $likeSearch;
}
$roomJoin = '';
$roomSelect = "NULL AS destination_room_label";
if (sm_table_exists($pdo, 'rooms')) {
    $roomLabelCol = sm_column_exists($pdo, 'rooms', 'room_no') ? 'room_no' : (sm_column_exists($pdo, 'rooms', 'room_number') ? 'room_number' : 'id');
    $roomJoin = " LEFT JOIN rooms dr ON dr.id = sm.destination_room_id ";
    $roomSelect = "dr.{$roomLabelCol} AS destination_room_label";
}

$movements = [];
$summary = [
    'rows' => 0,
    'qty_in' => 0,
    'qty_out' => 0,
    'in_value' => 0,
    'out_value' => 0,
];

try {
    $stmt = $pdo->prepare("
        SELECT
            sm.*,
            ii.item_name,
            ii.item_code,
            ii.avg_cost,
            c.category_name,
            u.unit_code,
            sl.location_name,
            sl.location_code,
            dsl.location_name AS destination_store_name,
            {$roomSelect}
        FROM stock_movements sm
        INNER JOIN inventory_items ii ON ii.id = sm.item_id
        LEFT JOIN inventory_item_categories c ON c.id = ii.category_id
        LEFT JOIN inventory_units u ON u.id = ii.unit_id
        INNER JOIN store_locations sl ON sl.id = sm.store_id
        LEFT JOIN store_locations dsl ON dsl.id = sm.destination_store_id
        {$roomJoin}
        WHERE $where
        ORDER BY sm.movement_date DESC, sm.id DESC
        LIMIT 700
    ");
    $stmt->execute($params);
    $movements = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($movements as $row) {
        $summary['rows']++;
        $summary['qty_in'] += (float)$row['qty_in'];
        $summary['qty_out'] += (float)$row['qty_out'];

        if ((float)$row['qty_in'] > 0) $summary['in_value'] += (float)$row['total_cost'];
        if ((float)$row['qty_out'] > 0) $summary['out_value'] += (float)$row['total_cost'];
    }
} catch (Throwable $e) {
    $errors[] = 'Could not load stock movements: ' . $e->getMessage();
}

$movementBatches = [];
foreach ($movements as $row) {
    $batchKey = trim((string)($row['batch_no'] ?? ''));
    if ($batchKey === '') {
        $batchKey = 'LEGACY-' . (int)$row['id'];
    }

    if (!isset($movementBatches[$batchKey])) {
        $movementBatches[$batchKey] = [
            'batch_no' => $row['batch_no'] ?: 'Legacy #' . (int)$row['id'],
            'raw_batch_no' => $row['batch_no'] ?: '',
            'movement_date' => $row['movement_date'],
            'origin' => $row['location_name'] ?? '',
            'destination' => sm_destination_label($row),
            'reference_type' => $row['reference_type'] ?? '',
            'reference_id' => $row['reference_id'] ?? null,
            'notes' => $row['notes'] ?? '',
            'types' => [],
            'line_count' => 0,
            'qty_in' => 0,
            'qty_out' => 0,
            'total_in_value' => 0,
            'total_out_value' => 0,
            'total_value' => 0,
            'locked' => false,
            'item_names' => [],
            'lines' => [],
        ];
    }

    $movementBatches[$batchKey]['line_count']++;
    $movementBatches[$batchKey]['qty_in'] += (float)$row['qty_in'];
    $movementBatches[$batchKey]['qty_out'] += (float)$row['qty_out'];
    $movementBatches[$batchKey]['total_value'] += (float)$row['total_cost'];

    if ((float)$row['qty_in'] > 0) {
        $movementBatches[$batchKey]['total_in_value'] += (float)$row['total_cost'];
    }
    if ((float)$row['qty_out'] > 0) {
        $movementBatches[$batchKey]['total_out_value'] += (float)$row['total_cost'];
    }

    $type = (string)$row['movement_type'];
    $movementBatches[$batchKey]['types'][$type] = true;

    $itemSummaryName = trim((string)($row['item_name'] ?? ''));
    if ($itemSummaryName !== '') {
        $movementBatches[$batchKey]['item_names'][$itemSummaryName] = true;
    }

    if (in_array((string)($row['reference_type'] ?? ''), ['POS','POS_VOID'], true)) {
        $movementBatches[$batchKey]['locked'] = true;
    }

    $movementBatches[$batchKey]['lines'][] = $row;
}


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

if (($_GET['export'] ?? '') === 'excel') {
    $filename = 'stock_movement_batches_' . 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:#fff;font-weight:bold;}';
    echo 'th,td{border:1px solid #d1d5db;padding:6px;vertical-align:top;}';
    echo '.right{text-align:right}.center{text-align:center}.title{font-size:18px;font-weight:bold;margin-bottom:4px}.batch{background:#f3f4f6;font-weight:bold}.line{background:#fff}.muted{color:#6b7280}';
    echo '</style></head><body>';

    echo '<div class="title">Stock Movement Batches Export</div>';
    echo '<div>Generated: ' . h(date('Y-m-d H:i:s')) . '</div>';
    echo '<div>Filters: From ' . h($dateFrom) . ' To ' . h($dateTo)
        . ' | Store: ' . h($filterStore > 0 ? (string)$filterStore : 'All')
        . ' | Item: ' . h($filterItem > 0 ? (string)$filterItem : 'All')
        . ' | Type: ' . h($filterType !== '' ? $filterType : 'All')
        . ' | Search: ' . h($search !== '' ? $search : 'All')
        . '</div><br>';

    echo '<table>';
    echo '<thead><tr>';
    foreach ([
        'Row Type','Date','Time','Batch','Multi-line','Line Count','Line No','Item Code','Item',
        'Origin','Destination','Movement Type','Qty In','Qty Out','Unit Cost','Line Value',
        'Batch Qty In','Batch Qty Out','Batch Value','Reference','Notes'
    ] as $head) {
        echo '<th>' . h($head) . '</th>';
    }
    echo '</tr></thead><tbody>';

    if (!$movementBatches) {
        echo '<tr><td colspan="21" class="center">No stock movement batches found.</td></tr>';
    } else {
        foreach ($movementBatches as $batch) {
            $types = array_keys($batch['types']);
            $displayValue = ((float)$batch['total_out_value'] > 0) ? (float)$batch['total_out_value'] : (float)$batch['total_in_value'];
            $isMulti = ((int)$batch['line_count'] > 1) ? 'YES' : 'NO';
            $itemsSummary = implode(', ', array_slice(array_keys($batch['item_names'] ?? []), 0, 8));
            if (!empty($batch['item_names']) && count($batch['item_names']) > 8) {
                $itemsSummary .= ' +' . (count($batch['item_names']) - 8) . ' more';
            }

            echo '<tr class="batch">';
            echo '<td>Batch Summary</td>';
            echo '<td>' . h(date('Y-m-d', strtotime($batch['movement_date']))) . '</td>';
            echo '<td>' . h(date('H:i', strtotime($batch['movement_date']))) . '</td>';
            echo '<td>' . h($batch['batch_no']) . '</td>';
            echo '<td>' . h($isMulti) . '</td>';
            echo '<td class="right">' . h((int)$batch['line_count']) . '</td>';
            echo '<td></td><td></td>';
            echo '<td>' . h($itemsSummary) . '</td>';
            echo '<td>' . h($batch['origin']) . '</td>';
            echo '<td>' . h($batch['destination']) . '</td>';
            echo '<td>' . h(implode(', ', array_map(fn($t) => str_replace('_', ' ', $t), $types))) . '</td>';
            echo '<td class="right"></td><td class="right"></td><td class="right"></td><td class="right"></td>';
            echo '<td class="right">' . h(money_fmt($batch['qty_in'])) . '</td>';
            echo '<td class="right">' . h(money_fmt($batch['qty_out'])) . '</td>';
            echo '<td class="right">' . h(money_fmt($displayValue)) . '</td>';
            echo '<td>' . h($batch['reference_type'] ?: '') . (!empty($batch['reference_id']) ? ' #' . h((int)$batch['reference_id']) : '') . '</td>';
            echo '<td>' . h($batch['notes'] ?: '') . '</td>';
            echo '</tr>';

            foreach ($batch['lines'] as $row) {
                echo '<tr class="line">';
                echo '<td>Line Detail</td>';
                echo '<td>' . h(date('Y-m-d', strtotime($row['movement_date']))) . '</td>';
                echo '<td>' . h(date('H:i', strtotime($row['movement_date']))) . '</td>';
                echo '<td>' . h($batch['batch_no']) . '</td>';
                echo '<td>' . h($isMulti) . '</td>';
                echo '<td class="right">' . h((int)$batch['line_count']) . '</td>';
                echo '<td class="right">' . h((int)($row['line_no'] ?? 1)) . '</td>';
                echo '<td>' . h($row['item_code'] ?: '') . '</td>';
                echo '<td>' . h($row['item_name'] ?: '') . '</td>';
                echo '<td>' . h($row['location_name'] ?: '') . '</td>';
                echo '<td>' . h(sm_destination_label($row)) . '</td>';
                echo '<td>' . h(str_replace('_',' ', (string)$row['movement_type'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['qty_in'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['qty_out'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['unit_cost'])) . '</td>';
                echo '<td class="right">' . h(money_fmt($row['total_cost'])) . '</td>';
                echo '<td class="right"></td><td class="right"></td><td class="right"></td>';
                echo '<td>' . h($row['reference_type'] ?: '') . (!empty($row['reference_id']) ? ' #' . h((int)$row['reference_id']) : '') . '</td>';
                echo '<td>' . h($row['notes'] ?: '') . '</td>';
                echo '</tr>';
            }
        }
    }

    echo '</tbody></table></body></html>';
    exit;
}


$balances = [];
try {
    $balanceWhere = "1=1";
    $balanceParams = [];

    if ($filterStore > 0) {
        $balanceWhere .= " AND sm.store_id = :store_id";
        $balanceParams[':store_id'] = $filterStore;
    }
    if ($filterItem > 0) {
        $balanceWhere .= " AND sm.item_id = :item_id";
        $balanceParams[':item_id'] = $filterItem;
    }

    $stmt = $pdo->prepare("
        SELECT
            sm.store_id,
            sl.location_name,
            ii.id AS item_id,
            ii.item_name,
            ii.item_code,
            u.unit_code,
            COALESCE(SUM(sm.qty_in - sm.qty_out),0) AS balance_qty,
            COALESCE(SUM((sm.qty_in - sm.qty_out) * sm.unit_cost),0) AS stock_value,
            ii.reorder_level
        FROM stock_movements sm
        INNER JOIN inventory_items ii ON ii.id = sm.item_id
        LEFT JOIN inventory_units u ON u.id = ii.unit_id
        INNER JOIN store_locations sl ON sl.id = sm.store_id
        WHERE $balanceWhere
        GROUP BY sm.store_id, sm.item_id
        HAVING ABS(balance_qty) > 0.0001
        ORDER BY sl.location_name ASC, ii.item_name ASC
        LIMIT 300
    ");
    $stmt->execute($balanceParams);
    $balances = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {}

$flashes = sm_get_flash();

/*$typeLabels = [
    'OPENING' => 'Opening Balance',
    'GRN' => 'GRN / Purchase',
    'ISSUE' => 'Issue / End Use',
    'TRANSFER' => 'Transfer Store to Store',
    'ADJUSTMENT_IN' => 'Adjustment In',
    'ADJUSTMENT_OUT' => 'Adjustment Out',
    'WASTAGE' => 'Wastage',
    'RETURN' => 'Return',
];*/
$typeLabels = [
    'ISSUE' => 'Issue / End Use',
    'TRANSFER' => 'Transfer Store to Store',
    'RETURN' => 'Return',
];
$movementBadge = function(string $type): string {
    if (in_array($type, ['OPENING','GRN','TRANSFER_IN','ADJUSTMENT_IN','RETURN'], true)) return 'text-bg-success';
    if (in_array($type, ['ISSUE','SALE','TRANSFER_OUT','ADJUSTMENT_OUT','WASTAGE'], true)) return 'text-bg-danger';
    return 'text-bg-secondary';
};

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-arrow-left-right"></i> Stores &amp; POS Inventory</div>
            <div class="hero-title mt-2">Stock Movements</div>
            <div class="hero-subtitle mt-2">
                Capture accountable stock movements with origin, destination and multiple product lines per transaction.
            </div>
        </div>
        <div class="col-lg-4 text-lg-end">
            <a href="stock_card.php<?php echo $filterItem > 0 ? ('?item_id=' . (int)$filterItem . ($filterStore > 0 ? '&store_id=' . (int)$filterStore : '')) : ''; ?>" class="btn btn-light me-2">
                <i class="bi bi-card-list me-2"></i>Stock Card
            </a>
            <a href="inventory_items.php" class="btn btn-light me-2">
                <i class="bi bi-box-seam me-2"></i>Items
            </a>
            <a href="store_locations.php" class="btn btn-outline-light">
                <i class="bi bi-shop me-2"></i>Stores
            </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-list-ul"></i></div>
            <div><div class="metric-label">Movement Lines</div><div class="metric-value"><?php echo (int)$summary['rows']; ?></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-arrow-down-circle"></i></div>
            <div><div class="metric-label">Qty In</div><div class="metric-value small-value"><?php echo money_fmt($summary['qty_in']); ?></div></div>
        </div>
    </div>
    <div class="col-md-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-danger-subtle text-danger"><i class="bi bi-arrow-up-circle"></i></div>
            <div><div class="metric-label">Qty Out</div><div class="metric-value small-value"><?php echo money_fmt($summary['qty_out']); ?></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-cash-stack"></i></div>
            <div><div class="metric-label">Net Value</div><div class="metric-value small-value"><?php echo money_fmt($summary['in_value'] - $summary['out_value']); ?></div></div>
        </div>
    </div>
</div>


<div class="stock-command-bar mb-3">
    <div class="command-copy">
        <div class="command-kicker">Inventory Control Workspace</div>
        <h5 class="mb-1">Process and review stock movements</h5>
        <div class="text-muted small">Post issues, store transfers and returns in a focused workspace. Movement history remains fully visible below.</div>
    </div>
    <div class="command-actions">
        <button type="button" class="process-action process-issue" data-movement-open="ISSUE">
            <span class="process-icon"><i class="bi bi-box-arrow-right"></i></span>
            <span><strong>Issue Stock</strong><small>End use / department</small></span>
        </button>
        <button type="button" class="process-action process-transfer" data-movement-open="TRANSFER">
            <span class="process-icon"><i class="bi bi-arrow-left-right"></i></span>
            <span><strong>Transfer</strong><small>Store to store</small></span>
        </button>
        <button type="button" class="process-action process-return" data-movement-open="RETURN">
            <span class="process-icon"><i class="bi bi-arrow-counterclockwise"></i></span>
            <span><strong>Return</strong><small>Receive stock back</small></span>
        </button>
        <button type="button" class="btn btn-primary command-new" data-movement-open="">
            <i class="bi bi-plus-circle me-2"></i>New Movement
        </button>
    </div>
</div>

<div class="row g-4 stock-workspace">
    <div class="col-12 movement-entry-column">

        <div class="card panel-card mb-4 movement-entry-card" id="movementEntryCard" aria-hidden="true">
            <div class="card-header d-flex justify-content-between align-items-center movement-modal-header">
                <div>
                    <div class="small text-muted text-uppercase fw-bold">Inventory Transaction</div>
                    <h5 class="mb-0">Post Stock Movement</h5>
                </div>
                <div class="d-flex align-items-center gap-2">
                    <span class="badge text-bg-light">Multi-line</span>
                    <button type="button" class="btn btn-sm btn-light movement-modal-close" id="closeMovementModal" aria-label="Close">
                        <i class="bi bi-x-lg"></i>
                    </button>
                </div>
            </div>
            <div class="card-body">
                <form method="post" id="movementForm">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="save_movement">

                    <div class="mb-3">
                        <label class="form-label">Movement Type</label>
                        <select name="movement_type" id="movementType" class="form-select" required>
                            <?php foreach ($typeLabels as $value => $label): ?>
                                <option value="<?php echo h($value); ?>"><?php echo h($label); ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>

                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="form-label">Place of Origin / From</label>
                            <select name="store_id" id="sourceStore" class="form-select" required>
                                <option value="">Select source store</option>
                                <?php foreach ($stores as $store): ?>
                                    <option value="<?php echo (int)$store['id']; ?>" <?php echo $filterStore === (int)$store['id'] ? 'selected' : ''; ?>>
                                        <?php echo h($store['location_name']); ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                            <div class="form-text">This is the location being credited or reduced.</div>
                        </div>

                        <div class="col-md-6 destination-type-wrap">
                            <label class="form-label">Destination Type</label>
                            <select name="destination_type" id="destinationType" class="form-select">
                                <option value="">Not applicable / Stock In</option>
                                <option value="STORE">Store / Department Store</option>
                                <option value="ROOM">Room / Lodge End Use</option>
                                <option value="DEPARTMENT">Department</option>
                                <option value="STAFF">Staff</option>
                                <option value="GUEST">Guest</option>
                                <option value="SUPPLIER">Supplier</option>
                                <option value="OTHER">Other</option>
                            </select>
                        </div>

                        <div class="col-md-6 destination-store-wrap" style="display:none;">
                            <label class="form-label">Destination Store</label>
                            <select name="to_store_id" id="toStore" class="form-select">
                                <option value="">Select destination store</option>
                                <?php foreach ($stores as $store): ?>
                                    <option value="<?php echo (int)$store['id']; ?>">
                                        <?php echo h($store['location_name']); ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                        </div>

                        <div class="col-md-6 destination-room-wrap" style="display:none;">
                            <label class="form-label">Destination Room</label>
                            <select name="destination_room_id" class="form-select">
                                <option value="">Select room / or type below</option>
                                <?php foreach ($rooms as $room): ?>
                                    <option value="<?php echo (int)$room['id']; ?>"><?php echo h($room['room_label']); ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>

                        <div class="col-12 destination-name-wrap" style="display:none;">
                            <label class="form-label">Destination Details</label>
                            <input type="text" name="destination_name" id="destinationName" class="form-control" placeholder="e.g. Room 12 minibar, Housekeeping, Maintenance workshop, Staff meal, Guest amenity">
                        </div>
                    </div>

                    <div class="row g-3 mt-0">
                        <div class="col-md-4">
                            <label class="form-label">Movement Date</label>
                            <input type="datetime-local" name="movement_date" class="form-control" value="<?php echo h(date('Y-m-d\TH:i')); ?>">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Reference Type</label>
                            <input type="text" name="reference_type" class="form-control" value="Manual" placeholder="Manual / Supplier Invoice">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">Reference ID</label>
                            <input type="number" name="reference_id" class="form-control" placeholder="Optional">
                        </div>
                    </div>

                    <hr class="my-4">

                    <div class="d-flex justify-content-between align-items-center mb-2">
                        <div>
                            <h6 class="mb-0">Product Lines</h6>
                            <div class="text-muted small">For bulk conversions, select the outlet item to receive, for example Rum 25ml Tot. The system deducts the linked bulk item.</div>
                        </div>
                        <button type="button" class="btn btn-sm btn-outline-primary" id="addLineBtn">
                            <i class="bi bi-plus-circle me-1"></i>Add Line
                        </button>
                    </div>

                    <div id="movementLines" class="movement-lines">
                        <div class="movement-line-card">
                            <div class="d-flex justify-content-between align-items-center mb-2">
                                <strong>Line 1</strong>
                                <button type="button" class="btn btn-sm btn-outline-danger remove-line" title="Remove line" style="display:none;"><i class="bi bi-x-lg"></i></button>
                            </div>
                            <div class="row g-2">
                                <div class="col-md-6">
                                    <label class="form-label">Item to Move / Receive</label>
                                    <select name="item_id[]" class="form-select item-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-unit="<?php echo h($item['unit_code'] ?: ''); ?>">
                                                <?php echo h($item['item_name']); ?><?php echo $item['item_code'] ? ' - ' . h($item['item_code']) : ''; ?>
                                            </option>
                                        <?php endforeach; ?>
                                    </select>
                                    <div class="stock-help small text-muted mt-1">For converted transfers, select the outlet item to receive; the source bulk item is deducted automatically.</div>
                                </div>
                                <div class="col-md-3">
                                    <label class="form-label">Quantity</label>
                                    <input type="number"     step="0.0001"  min="0.0001" name="qty[]" class="form-control qty-input" required>
                                </div>
                                <div class="col-md-3">
                                    <label class="form-label">Unit Cost</label>
                                    <input type="number" step="0.0001" min="0" name="unit_cost[]" class="form-control cost-input">
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="movement-total-box mt-3">
                        <div>
                            <span class="text-muted small">Lines</span>
                            <strong id="lineCount">0</strong>
                        </div>
                        <div>
                            <span class="text-muted small">Estimated Value</span>
                            <strong id="estimatedValue">0.00</strong>
                        </div>
                    </div>

                    <div class="mt-3">
                        <label class="form-label">Notes</label>
                        <textarea name="notes" class="form-control" rows="3" placeholder="Supplier, reason, issue authorisation, end-use details..."></textarea>
                    </div>

                    <div class="alert alert-info mt-3 small mb-0">
                        <strong>Accountability:</strong> Issues, wastage and outward adjustments require a destination. Transfers create matching OUT and IN lines under one batch number.
                        If the selected destination item has a conversion setup, the system deducts the bulk/source item and receives the converted outlet item automatically.
                    </div>

                    <button class="btn btn-primary w-100 mt-3">
                        <i class="bi bi-check-circle me-2"></i>Post Movement
                    </button>
                </form>
            </div>
        </div>

        <div class="card panel-card current-balances-card" id="currentBalancesCard">
            <div class="card-header d-flex justify-content-between align-items-center">
                <div>
                    <h5 class="mb-0">Current Stock Balances</h5>
                    <div class="small text-muted">Click an item to open its stock card.</div>
                </div>
                <span class="badge text-bg-light"><?php echo number_format(count($balances)); ?> balances</span>
            </div>
            <div class="card-body p-0 balance-list">
                <?php if (!$balances): ?>
                    <div class="text-center text-muted py-4">No balances yet.</div>
                <?php else: ?>
                    <?php foreach ($balances as $bal): ?>
                        <?php
                            $low = (float)$bal['reorder_level'] > 0 && (float)$bal['balance_qty'] <= (float)$bal['reorder_level'];
                            // Each balance row is a specific item in a specific store - exactly
                            // what the stock card wants - so link straight through with both
                            // pre-selected.
                            $cardUrl = 'stock_card.php?item_id=' . (int)$bal['item_id'] . '&store_id=' . (int)$bal['store_id'];
                        ?>
                        <a class="balance-row balance-row-link <?php echo $low ? 'is-low' : ''; ?>"
                           href="<?php echo h($cardUrl); ?>"
                           title="View stock card for this item in this store">
                            <div>
                                <strong><?php echo h($bal['item_name']); ?></strong>
                                <div class="small text-muted"><?php echo h($bal['location_name']); ?> • <?php echo h($bal['unit_code']); ?></div>
                            </div>
                            <div class="text-end">
                                <strong><?php echo money_fmt($bal['balance_qty']); ?></strong>
                                <div class="small text-muted"><?php echo money_fmt($bal['stock_value']); ?> <i class="bi bi-card-list ms-1"></i></div>
                            </div>
                        </a>
                    <?php endforeach; ?>
                <?php endif; ?>
            </div>
        </div>
    </div>

    <div class="col-12 movement-history-column">
        <div class="card panel-card mb-3 movement-filter-card">
            <div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
                <div>
                    <h5 class="mb-0">Movement Register</h5>
                    <div class="small text-muted">Filter, inspect and export every accountable stock movement.</div>
                </div>
                <div class="filter-result-pill"><i class="bi bi-list-check me-1"></i><?php echo number_format(count($movementBatches)); ?> batches</div>
            </div>
            <div class="card-body">
                <form method="get" class="row g-3 align-items-end movement-filter-form">
                    <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">Store</label>
                        <select name="store_id" class="form-select">
                            <option value="0">All stores</option>
                            <?php foreach ($stores as $store): ?>
                                <option value="<?php echo (int)$store['id']; ?>" <?php echo $filterStore === (int)$store['id'] ? 'selected' : ''; ?>>
                                    <?php echo h($store['location_name']); ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="col-md-2">
                        <label class="form-label">Item</label>
                        <select name="item_id" class="form-select">
                            <option value="0">All items</option>
                            <?php foreach ($items as $item): ?>
                                <option value="<?php echo (int)$item['id']; ?>" <?php echo $filterItem === (int)$item['id'] ? 'selected' : ''; ?>>
                                    <?php echo h($item['item_name']); ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="col-md-1">
                        <label class="form-label">Type</label>
                        <select name="movement_type" class="form-select">
                            <option value="">All</option>
                            <?php foreach (['OPENING','GRN','ISSUE','SALE','TRANSFER_IN','TRANSFER_OUT','ADJUSTMENT_IN','ADJUSTMENT_OUT','WASTAGE','RETURN'] as $type): ?>
                                <option value="<?php echo h($type); ?>" <?php echo $filterType === $type ? 'selected' : ''; ?>>
                                    <?php echo h(str_replace('_',' ', $type)); ?>
                                </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" title="Filter"><i class="bi bi-funnel"></i></button>
                    </div>
                    <div class="col-md-1 d-grid">
                        <button type="submit" name="export" value="excel" class="btn btn-success" title="Export filtered batches to Excel"><i class="bi bi-file-earmark-excel"></i></button>
                    </div>
                </form>
            </div>
        </div>

        <div class="card panel-card">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="mb-0">Stock Movement History</h5>
                <div class="d-flex align-items-center gap-2 flex-wrap">
                    <span class="text-muted small">Latest grouped batches — expand any row to inspect product lines</span>
                    <a href="<?php echo h($exportUrl); ?>" class="btn btn-sm btn-success"><i class="bi bi-file-earmark-excel me-1"></i>Excel</a>
                </div>
            </div>
            <div class="card-body p-0">
                <div class="movements-table-wrap">
                    <table class="table table-modern align-middle mb-0 movements-table batch-table">
                        <thead>
                        <tr>
                            <th style="width:42px;"></th>
                            <th>Date</th>
                            <th>Batch</th>
                            <th>Origin</th>
                            <th>Destination</th>
                            <th>Type(s)</th>
                            <th class="text-end">Lines</th>
                            <th class="text-end">Qty In</th>
                            <th class="text-end">Qty Out</th>
                            <th class="text-end">Value</th>
                            <th>Reference</th>
                            <th class="text-end">Action</th>
                        </tr>
                        </thead>
                        <tbody>
                        <?php if (!$movementBatches): ?>
                            <tr><td colspan="12" class="text-center text-muted py-4">No stock movements found.</td></tr>
                        <?php else: ?>
                            <?php $batchIndex = 0; ?>
                            <?php foreach ($movementBatches as $batchKey => $batch): ?>
                                <?php
                                    $batchIndex++;
                                    $detailId = 'batchLines_' . $batchIndex;
                                    $types = array_keys($batch['types']);
                                    $displayValue = ((float)$batch['total_out_value'] > 0)
                                        ? (float)$batch['total_out_value']
                                        : (float)$batch['total_in_value'];
                                ?>
                                <tr class="batch-summary-row">
                                    <td>
                                        <button type="button"
                                                class="btn btn-sm btn-light batch-toggle"
                                                data-target="<?php echo h($detailId); ?>"
                                                title="View batch lines">
                                            <i class="bi bi-chevron-down"></i>
                                        </button>
                                    </td>
                                    <td>
                                        <strong><?php echo h(date('Y-m-d', strtotime($batch['movement_date']))); ?></strong>
                                        <div class="small text-muted"><?php echo h(date('H:i', strtotime($batch['movement_date']))); ?></div>
                                    </td>
                                    <td>
                                        <span class="badge text-bg-dark"><?php echo h($batch['batch_no']); ?></span>
                                        <?php if ((int)$batch['line_count'] > 1): ?>
                                            <div class="small mt-1"><span class="badge text-bg-warning">Multi-line batch</span></div>
                                        <?php endif; ?>
                                        <div class="small text-muted">
                                            <?php
                                                $batchItems = array_keys($batch['item_names'] ?? []);
                                                $batchItemText = implode(', ', array_slice($batchItems, 0, 3));
                                                if (count($batchItems) > 3) $batchItemText .= ' +' . (count($batchItems) - 3) . ' more';
                                                echo h($batchItemText ?: 'Grouped transaction');
                                            ?>
                                        </div>
                                    </td>
                                    <td><?php echo h($batch['origin']); ?></td>
                                    <td><?php echo h($batch['destination']); ?></td>
                                    <td>
                                        <?php foreach ($types as $type): ?>
                                            <span class="badge <?php echo h($movementBadge($type)); ?> me-1 mb-1"><?php echo h(str_replace('_',' ', $type)); ?></span>
                                        <?php endforeach; ?>
                                    </td>
                                    <td class="text-end fw-bold"><?php echo (int)$batch['line_count']; ?></td>
                                    <td class="text-end text-success fw-bold"><?php echo money_fmt($batch['qty_in']); ?></td>
                                    <td class="text-end text-danger fw-bold"><?php echo money_fmt($batch['qty_out']); ?></td>
                                    <td class="text-end fw-bold"><?php echo money_fmt($displayValue); ?></td>
                                    <td>
                                        <?php echo h($batch['reference_type'] ?: ''); ?>
                                        <?php if (!empty($batch['reference_id'])): ?>
                                            <div class="small text-muted">#<?php echo (int)$batch['reference_id']; ?></div>
                                        <?php endif; ?>
                                        <?php if (!empty($batch['notes'])): ?>
                                            <div class="small text-muted"><?php echo h($batch['notes']); ?></div>
                                        <?php endif; ?>
                                    </td>
                                    <td class="text-end">
                                        <?php if (!$batch['locked'] && $batch['raw_batch_no'] !== ''): ?>
                                            <form method="post" onsubmit="return confirm('Delete this whole stock movement batch and all its lines?');">
                                                <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                                                <input type="hidden" name="action" value="delete_batch">
                                                <input type="hidden" name="batch_no" value="<?php echo h($batch['raw_batch_no']); ?>">
                                                <button class="btn btn-sm btn-outline-danger" title="Delete whole batch">
                                                    <i class="bi bi-trash"></i>
                                                </button>
                                            </form>
                                        <?php elseif ($batch['locked']): ?>
                                            <span class="badge text-bg-secondary">Locked</span>
                                        <?php else: ?>
                                            <span class="badge text-bg-light">Legacy</span>
                                        <?php endif; ?>
                                    </td>
                                </tr>

                                <tr id="<?php echo h($detailId); ?>" class="batch-detail-row" style="display:none;">
                                    <td colspan="12" class="p-0">
                                        <div class="batch-detail-box">
                                            <div class="batch-detail-title">
                                                <i class="bi bi-list-check me-2"></i>Batch Lines
                                                <span class="text-muted ms-2"><?php echo h($batch['batch_no']); ?></span>
                                            </div>

                                            <div class="table-responsive">
                                                <table class="table table-sm align-middle mb-0 batch-lines-table">
                                                    <thead>
                                                    <tr>
                                                        <th>Line</th>
                                                        <th>Item</th>
                                                        <th>Origin</th>
                                                        <th>Destination</th>
                                                        <th>Type</th>
                                                        <th class="text-end">In</th>
                                                        <th class="text-end">Out</th>
                                                        <th class="text-end">Unit Cost</th>
                                                        <th class="text-end">Total</th>
                                                        <th class="text-end">Action</th>
                                                    </tr>
                                                    </thead>
                                                    <tbody>
                                                    <?php foreach ($batch['lines'] as $row): ?>
                                                        <tr>
                                                            <td>
                                                                <span class="badge text-bg-light">Line <?php echo (int)($row['line_no'] ?? 1); ?></span>
                                                            </td>
                                                            <td>
                                                                <strong><?php echo h($row['item_name']); ?></strong>
                                                                <div class="small text-muted"><?php echo h($row['item_code'] ?: ''); ?> <?php echo h($row['unit_code'] ?: ''); ?></div>
                                                                <?php if (!empty($row['conversion_label'])): ?>
                                                                    <div class="small text-primary fw-semibold"><i class="bi bi-arrow-repeat me-1"></i><?php echo h($row['conversion_label']); ?></div>
                                                                <?php endif; ?>
                                                            </td>
                                                            <td><?php echo h($row['location_name']); ?></td>
                                                            <td><?php echo h(sm_destination_label($row)); ?></td>
                                                            <td><span class="badge <?php echo h($movementBadge($row['movement_type'])); ?>"><?php echo h(str_replace('_',' ', $row['movement_type'])); ?></span></td>
                                                            <td class="text-end text-success fw-bold"><?php echo money_fmt($row['qty_in']); ?></td>
                                                            <td class="text-end text-danger fw-bold"><?php echo money_fmt($row['qty_out']); ?></td>
                                                            <td class="text-end"><?php echo money_fmt($row['unit_cost']); ?></td>
                                                            <td class="text-end fw-bold"><?php echo money_fmt($row['total_cost']); ?></td>
                                                            <td class="text-end">
                                                                <?php if (!in_array($row['reference_type'], ['POS','POS_VOID'], true)): ?>
                                                                    <form method="post" onsubmit="return confirm('Delete this stock movement line?');">
                                                                        <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                                                                        <input type="hidden" name="action" value="delete_movement">
                                                                        <input type="hidden" name="id" value="<?php echo (int)$row['id']; ?>">
                                                                        <button class="btn btn-sm btn-outline-danger" title="Delete line"><i class="bi bi-trash"></i></button>
                                                                    </form>
                                                                <?php else: ?>
                                                                    <span class="badge text-bg-secondary">Locked</span>
                                                                <?php endif; ?>
                                                            </td>
                                                        </tr>
                                                    <?php endforeach; ?>
                                                    </tbody>
                                                </table>
                                            </div>
                                        </div>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                        <?php endif; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <div class="alert alert-info mt-4">
            <strong>Important:</strong> POS sale movements are locked here. Void the POS order from <a href="/rooms/modules/pos/pos_orders.php">POS Orders</a> to reverse stock properly.
        </div>
    </div>
</div>


<div class="movement-modal-backdrop" id="movementModalBackdrop" aria-hidden="true"></div>

<style>

/* Purchase-order inspired stock movement workspace */

/* Ultra compact top / filter area */
.hero-band{padding:10px 14px!important;margin-bottom:8px!important}
.hero-title{font-size:1.25rem!important;line-height:1.1!important;margin-top:2px!important}
.hero-subtitle{font-size:.78rem!important;line-height:1.2!important;margin-top:2px!important}
.page-eyebrow{font-size:.68rem!important;letter-spacing:.06em!important}
.hero-band .btn{padding:5px 9px!important;font-size:.78rem!important;border-radius:8px!important}
.row.g-4.mb-4{margin-bottom:8px!important;--bs-gutter-x:.65rem!important;--bs-gutter-y:.65rem!important}
.metric-card{padding:8px 10px!important;gap:6px!important;min-height:52px!important}
.metric-icon{width:30px!important;height:30px!important;border-radius:8px!important;font-size:12px!important}
.metric-label{font-size:.68rem!important;margin-bottom:1px!important}
.metric-value{font-size:.95rem!important;line-height:1.05!important}
.panel-card .card-header{padding:9px 12px!important}
.panel-card .card-body{padding:10px!important}
.form-label{font-size:.7rem!important;margin-bottom:2px!important;font-weight:700!important}
.form-control,.form-select{height:31px!important;min-height:31px!important;font-size:.8rem!important;padding:3px 7px!important;border-radius:8px!important}
textarea.form-control{height:auto!important;min-height:44px!important}
.row.g-3{--bs-gutter-x:.5rem!important;--bs-gutter-y:.45rem!important}
.small-value{font-size:1rem!important;letter-spacing:0!important}
.balance-list{max-height:520px;overflow:auto}
.balance-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:13px 16px;border-bottom:1px solid rgba(15,23,42,.08)}
.balance-row.is-low{background:#fff7ed}
.balance-row:last-child{border-bottom:0}
/* Balance rows are links to the stock card - keep them looking like rows, not
   underlined anchors, and give a hover cue that they are clickable. */
.balance-row-link{text-decoration:none;color:inherit;transition:background .12s ease}
.balance-row-link:hover{background:#f1f5f9}
.balance-row-link.is-low:hover{background:#ffedd5}
.movement-lines{display:flex;flex-direction:column;gap:10px}
.movement-line-card{border:1px solid rgba(15,23,42,.10);border-radius:16px;padding:12px;background:#fff;box-shadow:0 8px 22px rgba(15,23,42,.04)}
.movement-line-card .form-label{font-size:.78rem;color:#64748b;margin-bottom:4px}
.movement-total-box{display:flex;justify-content:space-between;align-items:center;border:1px solid rgba(15,23,42,.10);background:#f8fafc;border-radius:16px;padding:12px 14px}
.movements-table-wrap{max-height:650px;overflow:auto;position:relative}
.movements-table thead th{position:sticky;top:0;z-index:50;background:#ffffff;color:#0f172a;box-shadow:0 2px 6px rgba(15,23,42,.12);border-bottom:2px solid #e2e8f0;white-space:nowrap}
.movements-table td{vertical-align:top}
.batch-summary-row{background:#fff}
.batch-summary-row:hover{background:#f8fafc}
.batch-toggle{border:1px solid rgba(15,23,42,.12);border-radius:10px}
.batch-toggle.is-open i{transform:rotate(180deg)}
.batch-toggle i{transition:transform .18s ease}
.batch-detail-box{background:#f8fafc;border-top:1px solid #e2e8f0;border-bottom:1px solid #e2e8f0;padding:14px 16px}
.batch-detail-title{font-weight:700;margin-bottom:10px;color:#0f172a}
.batch-lines-table{background:#fff;border:1px solid #e2e8f0;border-radius:14px;overflow:hidden}
.batch-lines-table thead th{font-size:.78rem;text-transform:uppercase;letter-spacing:.04em;color:#64748b;background:#f1f5f9}
.stock-help{min-height:18px}
.stock-help.is-ok{color:#047857!important;font-weight:600}
.stock-help.is-empty{color:#b91c1c!important;font-weight:600}
.stock-help.is-warn{color:#b45309!important;font-weight:600}
.native-item-picker{position:relative;width:100%;z-index:30}
.native-item-picker.is-open{z-index:9999}
.native-item-picker .item-search-input{background:#fff}
.native-item-picker .item-search-list{display:none;position:absolute;left:0;right:0;top:calc(100% + 4px);max-height:260px;overflow:auto;background:#fff;border:1px solid #cbd5e1;border-radius:12px;box-shadow:0 18px 35px rgba(15,23,42,.20);padding:6px;z-index:10000}
.native-item-picker.is-open .item-search-list{display:block}
.native-item-picker .item-search-option{display:block;width:100%;text-align:left;border:0;background:#fff;border-radius:9px;padding:8px 10px;font-size:.82rem;color:#111827;line-height:1.2}
.native-item-picker .item-search-option:hover,.native-item-picker .item-search-option.is-active{background:#eff6ff;color:#1d4ed8}
.native-item-picker .item-search-option .meta{display:block;font-size:.72rem;color:#64748b;margin-top:2px}
.native-item-picker .item-search-empty{padding:10px;color:#64748b;font-size:.8rem;text-align:center}
.movement-line-card,.movement-lines,.panel-card .card-body,form#movementForm{overflow:visible!important}

.conversion-meta{
    color:#0f766e !important;
    font-weight:700;
}
.stock-help.is-ok strong{
    color:#0f766e;
}

.stock-command-bar{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:18px;
    padding:15px 17px;
    background:#fff;
    border:1px solid #e2e8f0;
    border-radius:18px;
    box-shadow:0 12px 32px rgba(15,23,42,.07);
}
.command-kicker{
    font-size:.68rem;
    letter-spacing:.09em;
    text-transform:uppercase;
    font-weight:800;
    color:#2563eb;
}
.command-actions{display:flex;align-items:stretch;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.process-action{
    display:flex;align-items:center;gap:9px;
    min-width:145px;padding:8px 11px;
    background:#fff;border:1px solid #e2e8f0;border-radius:12px;
    color:#0f172a;text-align:left;transition:.15s ease;
}
.process-action:hover{transform:translateY(-1px);border-color:#94a3b8;box-shadow:0 8px 18px rgba(15,23,42,.08)}
.process-action strong,.process-action small{display:block}
.process-action strong{font-size:.79rem}
.process-action small{font-size:.67rem;color:#64748b;margin-top:1px}
.process-icon{width:31px;height:31px;display:grid;place-items:center;border-radius:9px;font-size:.9rem}
.process-issue .process-icon{background:#fff7ed;color:#c2410c}
.process-transfer .process-icon{background:#eff6ff;color:#1d4ed8}
.process-return .process-icon{background:#ecfdf5;color:#047857}
.command-new{border-radius:12px!important;padding-inline:16px!important}
.stock-workspace{display:flex}
.movement-history-column{order:1}
.movement-entry-column{order:2}
.current-balances-card{margin-top:16px}
.current-balances-card .balance-list{
    display:grid;
    grid-template-columns:repeat(3,minmax(0,1fr));
    max-height:420px;
}
.current-balances-card .balance-row{
    min-width:0;border-right:1px solid rgba(15,23,42,.08)
}
.current-balances-card .balance-row:nth-child(3n){border-right:0}
.movement-filter-card .card-header{background:linear-gradient(180deg,#fff,#f8fafc)}
.filter-result-pill{
    border:1px solid #dbeafe;background:#eff6ff;color:#1d4ed8;
    border-radius:999px;padding:5px 10px;font-size:.75rem;font-weight:700
}
.movement-filter-form{
    display:grid!important;
    grid-template-columns:repeat(2,minmax(125px,.8fr)) minmax(170px,1fr) minmax(210px,1.4fr) minmax(120px,.7fr) minmax(170px,1fr) 40px 40px;
    gap:8px!important
}
.movement-filter-form > div{width:auto!important;max-width:none!important;padding:0!important}
.movement-entry-card{
    display:none;
    position:fixed;
    inset:20px;
    z-index:1065;
    margin:0!important;
    border:0!important;
    border-radius:20px!important;
    box-shadow:0 30px 80px rgba(15,23,42,.35)!important;
    overflow:hidden!important;
}
.movement-entry-card.is-open{display:flex;flex-direction:column}
.movement-entry-card > .card-header{flex:0 0 auto;padding:14px 18px!important;border-bottom:1px solid #e2e8f0;background:#fff}
.movement-entry-card > .card-body{flex:1 1 auto;overflow:auto!important;padding:16px 18px!important;background:#f8fafc}
.movement-entry-card form#movementForm{
    max-width:1500px;margin:0 auto;padding:16px;
    background:#fff;border:1px solid #e2e8f0;border-radius:16px;
    box-shadow:0 10px 28px rgba(15,23,42,.05)
}
.movement-modal-close{width:34px;height:34px;border-radius:10px}
.movement-modal-backdrop{
    display:none;position:fixed;inset:0;z-index:1060;
    background:rgba(15,23,42,.72);backdrop-filter:blur(3px)
}
.movement-modal-backdrop.is-open{display:block}
body.movement-modal-open{overflow:hidden}
.movement-entry-card .movement-lines{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:10px;
}
.movement-entry-card .movement-line-card{
    border-radius:12px;padding:10px;box-shadow:none;background:#f8fafc
}
.movement-entry-card .native-item-picker .item-search-list{max-height:230px}
.batch-summary-row td{padding-top:10px!important;padding-bottom:10px!important}
.batch-summary-row{
    border-left:3px solid transparent;
    transition:background .12s ease,border-color .12s ease;
}
.batch-summary-row:hover{border-left-color:#3b82f6}
.batch-table .badge{font-size:.68rem}
.batch-detail-box{border-radius:0 0 14px 14px}
.movements-table-wrap{max-height:720px;border-radius:0 0 16px 16px}
.panel-card{border:1px solid #e2e8f0!important;box-shadow:0 10px 28px rgba(15,23,42,.06)!important;border-radius:16px!important}
@media(max-width:1200px){
    .stock-command-bar{align-items:flex-start;flex-direction:column}
    .command-actions{width:100%;justify-content:flex-start}
    .movement-filter-form{grid-template-columns:repeat(4,minmax(0,1fr))}
    .current-balances-card .balance-list{grid-template-columns:repeat(2,minmax(0,1fr))}
    .current-balances-card .balance-row:nth-child(3n){border-right:1px solid rgba(15,23,42,.08)}
    .current-balances-card .balance-row:nth-child(2n){border-right:0}
}
@media(max-width:768px){
    .process-action{min-width:calc(50% - 4px);flex:1}
    .command-new{width:100%}
    .movement-filter-form{grid-template-columns:repeat(2,minmax(0,1fr))}
    .movement-entry-card{inset:8px;border-radius:14px!important}
    .movement-entry-card .movement-lines{grid-template-columns:1fr}
    .current-balances-card .balance-list{grid-template-columns:1fr}
    .current-balances-card .balance-row{border-right:0!important}
}

</style>

<script>
document.addEventListener('DOMContentLoaded', function(){
    const movementEntryCard = document.getElementById('movementEntryCard');
    const movementBackdrop = document.getElementById('movementModalBackdrop');
    const closeMovementModal = document.getElementById('closeMovementModal');

    function openMovementWorkspace(type){
        if (!movementEntryCard || !movementBackdrop) return;
        movementEntryCard.classList.add('is-open');
        movementBackdrop.classList.add('is-open');
        movementEntryCard.setAttribute('aria-hidden','false');
        movementBackdrop.setAttribute('aria-hidden','false');
        document.body.classList.add('movement-modal-open');

        const typeSelect = document.getElementById('movementType');
        if (type && typeSelect) {
            typeSelect.value = type;
            typeSelect.dispatchEvent(new Event('change', {bubbles:true}));
        }
        setTimeout(function(){
            const first = movementEntryCard.querySelector('select, input, textarea');
            if (first) first.focus();
        },80);
    }

    function closeMovementWorkspace(){
        if (!movementEntryCard || !movementBackdrop) return;
        movementEntryCard.classList.remove('is-open');
        movementBackdrop.classList.remove('is-open');
        movementEntryCard.setAttribute('aria-hidden','true');
        movementBackdrop.setAttribute('aria-hidden','true');
        document.body.classList.remove('movement-modal-open');
    }

    document.querySelectorAll('[data-movement-open]').forEach(function(button){
        button.addEventListener('click', function(){
            openMovementWorkspace(this.getAttribute('data-movement-open') || '');
        });
    });
    if (closeMovementModal) closeMovementModal.addEventListener('click', closeMovementWorkspace);
    if (movementBackdrop) movementBackdrop.addEventListener('click', closeMovementWorkspace);
    document.addEventListener('keydown', function(event){
        if (event.key === 'Escape' && movementEntryCard && movementEntryCard.classList.contains('is-open')) {
            closeMovementWorkspace();
        }
    });

    const movementType = document.getElementById('movementType');
    const sourceStore = document.getElementById('sourceStore');
    const destinationType = document.getElementById('destinationType');
    const destinationStoreWrap = document.querySelector('.destination-store-wrap');
    const destinationRoomWrap = document.querySelector('.destination-room-wrap');
    const destinationNameWrap = document.querySelector('.destination-name-wrap');
    const destinationTypeWrap = document.querySelector('.destination-type-wrap');
    const destinationName = document.getElementById('destinationName');
    const movementLines = document.getElementById('movementLines');
    const addLineBtn = document.getElementById('addLineBtn');
    const lineCount = document.getElementById('lineCount');
    const estimatedValue = document.getElementById('estimatedValue');

    const inventoryItems = <?php echo json_encode(array_map(function($item) use ($stockAvailabilityByStore){
        $balances = [];
        foreach ($stockAvailabilityByStore as $storeId => $storeBalances) {
            $balances[(string)$storeId] = (float)($storeBalances[(int)$item['id']] ?? 0);
        }
        return [
            'id' => (int)$item['id'],
            'label' => (string)$item['item_name'] . (!empty($item['item_code']) ? ' - ' . (string)$item['item_code'] : ''),
            'cost' => (float)($item['avg_cost'] ?: $item['cost_price']),
            'unit' => (string)($item['unit_code'] ?: ''),
            'balances' => $balances,
        ];
    }, $items), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); ?> || [];

    const inventoryConversions = <?php echo json_encode(array_map(function($conv) use ($stockAvailabilityByStore){
        $sourceBalances = [];
        foreach ($stockAvailabilityByStore as $storeId => $storeBalances) {
            $sourceBalances[(string)$storeId] = (float)($storeBalances[(int)$conv['source_item_id']] ?? 0);
        }

        $sourceQty = (float)($conv['source_qty'] ?? 1);
        $destinationQty = (float)($conv['destination_qty'] ?? 1);
        $factor = ($sourceQty > 0) ? ($destinationQty / $sourceQty) : 1;

        $sourceLabel = trim((string)$conv['source_item_name'] . (!empty($conv['source_item_code']) ? ' - ' . (string)$conv['source_item_code'] : ''));
        $destinationLabel = trim((string)$conv['destination_item_name'] . (!empty($conv['destination_item_code']) ? ' - ' . (string)$conv['destination_item_code'] : ''));

        return [
            'id' => (int)$conv['id'],
            'source_item_id' => (int)$conv['source_item_id'],
            'destination_item_id' => (int)$conv['destination_item_id'],
            'source_qty' => $sourceQty,
            'destination_qty' => $destinationQty,
            'factor' => $factor,
            'allow_fractional_source' => (int)($conv['allow_fractional_source'] ?? 0),
            'round_source_up' => (int)($conv['round_source_up'] ?? 0),
            'conversion_name' => (string)($conv['conversion_name'] ?: ''),
            'source_label' => $sourceLabel,
            'destination_label' => $destinationLabel,
            'source_unit' => (string)($conv['source_unit_code'] ?: ''),
            'destination_unit' => (string)($conv['destination_unit_code'] ?: ''),
            'source_balances' => $sourceBalances,
        ];
    }, $conversionRulesForJs), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); ?> || [];


    function stockOutNeedsDestination(){
        return movementType && ['ISSUE','TRANSFER','ADJUSTMENT_OUT','WASTAGE'].includes(movementType.value);
    }

    function setRequired(el, yes){
        if (!el) return;
        if (yes) el.setAttribute('required', 'required');
        else el.removeAttribute('required');
    }

    function show(el, yes){
        if (el) el.style.display = yes ? '' : 'none';
    }

    function toggleDestination(){
        const type = movementType ? movementType.value : '';
        const dest = destinationType ? destinationType.value : '';

        const toStore = document.getElementById('toStore');
        const roomSelect = document.querySelector('[name="destination_room_id"]');

        if (type === 'TRANSFER') {
            if (destinationType) destinationType.value = 'STORE';

            show(destinationTypeWrap, false);
            show(destinationStoreWrap, true);
            show(destinationRoomWrap, false);
            show(destinationNameWrap, false);

            setRequired(toStore, true);
            setRequired(roomSelect, false);
            setRequired(destinationName, false);
            return;
        }

        if (!stockOutNeedsDestination()) {
            if (destinationType) destinationType.value = '';

            show(destinationTypeWrap, false);
            show(destinationStoreWrap, false);
            show(destinationRoomWrap, false);
            show(destinationNameWrap, false);

            setRequired(toStore, false);
            setRequired(roomSelect, false);
            setRequired(destinationName, false);
            return;
        }

        show(destinationTypeWrap, true);

        show(destinationStoreWrap, dest === 'STORE');
        show(destinationRoomWrap, dest === 'ROOM');
        show(destinationNameWrap, !!dest && dest !== 'STORE');

        setRequired(toStore, dest === 'STORE');
        setRequired(roomSelect, false);

        // For rooms we allow either choosing a room from the dropdown or typing details.
        // For other non-store destinations, details must be typed.
        setRequired(destinationName, !!dest && dest !== 'STORE' && dest !== 'ROOM');

        if (!destinationName) return;

        if (dest === 'ROOM') {
            destinationName.placeholder = 'Optional: Room 12 minibar, guest amenity, room maintenance';
        } else if (dest === 'DEPARTMENT') {
            destinationName.placeholder = 'e.g. Housekeeping, Kitchen, Maintenance, Laundry';
        } else if (dest === 'STAFF') {
            destinationName.placeholder = 'e.g. Staff name / staff meal / uniform issue';
        } else if (dest === 'GUEST') {
            destinationName.placeholder = 'e.g. Guest name / booking reference';
        } else if (dest === 'SUPPLIER') {
            destinationName.placeholder = 'e.g. Supplier name / return note';
        } else {
            destinationName.placeholder = 'Destination details';
        }
    }

    function isStockOutSelection(){
        return movementType && ['ISSUE','TRANSFER','ADJUSTMENT_OUT','WASTAGE'].includes(movementType.value);
    }

    function currentStoreId(){
        return sourceStore ? String(sourceStore.value || '') : '';
    }

    function availableQtyForItem(item){
        const sid = currentStoreId();
        if (!sid || !item || !item.balances) return 0;
        const val = parseFloat(item.balances[sid] || '0') || 0;
        return val;
    }

    function formatQty(value){
        const num = parseFloat(value || '0') || 0;
        return num.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 4});
    }

    function conversionForDestination(itemId){
        if (!itemId || movementType?.value !== 'TRANSFER') return null;
        return inventoryConversions.find(conv => String(conv.destination_item_id) === String(itemId)) || null;
    }

    function sourceAvailableForConversion(conv){
        const sid = currentStoreId();
        if (!sid || !conv || !conv.source_balances) return 0;
        return parseFloat(conv.source_balances[sid] || '0') || 0;
    }

    function maxDestinationQtyForConversion(conv){
        if (!conv) return 0;
        const sourceAvailable = sourceAvailableForConversion(conv);
        const rawMax = sourceAvailable * (parseFloat(conv.factor || '1') || 1);
        if (parseInt(conv.allow_fractional_source || 0, 10) === 1) return rawMax;
        return Math.floor(rawMax + 0.0000001);
    }

    function conversionPreviewText(conv, destinationQty){
        if (!conv) return '';
        const qty = parseFloat(destinationQty || '0') || 0;
        const factor = parseFloat(conv.factor || '1') || 1;
        let sourceIssue = factor > 0 ? qty / factor : 0;

        if (parseInt(conv.allow_fractional_source || 0, 10) !== 1) {
            if (parseInt(conv.round_source_up || 0, 10) === 1) {
                sourceIssue = Math.ceil(sourceIssue - 0.0000001);
            } else {
                sourceIssue = Math.round(sourceIssue);
            }
        }

        const sourcePart = `${formatQty(sourceIssue)} ${conv.source_unit || ''} ${conv.source_label || 'source item'}`.trim();
        const destPart = `${formatQty(qty)} ${conv.destination_unit || ''} ${conv.destination_label || 'destination item'}`.trim();
        return `${sourcePart} OUT → ${destPart} IN`;
    }

    function allowedItemsForCurrentMovement(){
        if (!isStockOutSelection()) return inventoryItems;
        if (!currentStoreId()) return [];

        if (movementType && movementType.value === 'TRANSFER') {
            return inventoryItems.filter(item => {
                if (availableQtyForItem(item) > 0.0000) return true;
                const conv = conversionForDestination(item.id);
                return conv && sourceAvailableForConversion(conv) > 0.0000;
            });
        }

        return inventoryItems.filter(item => availableQtyForItem(item) > 0.0000);
    }

    function closeAllItemPickers(except){
        document.querySelectorAll('.native-item-picker.is-open').forEach(picker => {
            if (picker !== except) picker.classList.remove('is-open');
        });
    }

    function makeItemOptionButton(item, searchText){
        const btn = document.createElement('button');
        btn.type = 'button';
        btn.className = 'item-search-option';

        const conv = conversionForDestination(item.id);
        const balance = conv ? maxDestinationQtyForConversion(conv) : availableQtyForItem(item);
        const sourceAvailable = conv ? sourceAvailableForConversion(conv) : balance;

        const label = isStockOutSelection()
            ? `${item.label} — Available ${formatQty(balance)} ${item.unit || ''}`
            : item.label;

        btn.dataset.value = String(item.id);
        btn.dataset.label = label;
        btn.dataset.cost = String(item.cost || 0);
        btn.dataset.unit = item.unit || '';
        btn.dataset.available = String(balance || 0);

        if (conv) {
            btn.innerHTML = `
                <strong>${escapeHtml(item.label)}</strong>
                <span class="meta conversion-meta">Converted transfer: ${escapeHtml(formatQty(sourceAvailable))} ${escapeHtml(conv.source_unit || '')} bulk available → max ${escapeHtml(formatQty(balance))} ${escapeHtml(conv.destination_unit || item.unit || '')}</span>
            `;
        } else {
            btn.innerHTML = `<strong>${escapeHtml(item.label)}</strong>${isStockOutSelection() ? `<span class="meta">Available ${escapeHtml(formatQty(balance))} ${escapeHtml(item.unit || '')}</span>` : ''}`;
        }

        return btn;
    }

    function escapeHtml(value){
        return String(value || '').replace(/[&<>'"]/g, function(ch){
            return {'&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#039;','\"':'&quot;'}[ch] || ch;
        });
    }

    function buildItemSelect(selectedValue){
        const picker = document.createElement('div');
        picker.className = 'native-item-picker';

        const hidden = document.createElement('input');
        hidden.type = 'hidden';
        hidden.name = 'item_id[]';
        hidden.className = 'item-select';
        hidden.required = true;

        const search = document.createElement('input');
        search.type = 'text';
        search.className = 'form-control item-search-input';
        search.autocomplete = 'off';
        search.placeholder = isStockOutSelection()
            ? (currentStoreId() ? 'Type to search available item...' : 'Select source store first')
            : 'Type to search item...';

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

        picker.appendChild(hidden);
        picker.appendChild(search);
        picker.appendChild(list);

        function selectItem(item){
            if (!item) return;

            const conv = conversionForDestination(item.id);
            const balance = conv ? maxDestinationQtyForConversion(conv) : availableQtyForItem(item);

            hidden.value = String(item.id);
            hidden.dataset.cost = String(item.cost || 0);
            hidden.dataset.unit = item.unit || '';
            hidden.dataset.available = String(balance || 0);
            hidden.dataset.conversionId = conv ? String(conv.id) : '';
            hidden.dataset.conversionLabel = conv ? (conv.conversion_name || 'Converted transfer') : '';
            hidden.dataset.sourceLabel = conv ? (conv.source_label || '') : '';
            hidden.dataset.sourceUnit = conv ? (conv.source_unit || '') : '';
            hidden.dataset.destinationUnit = conv ? (conv.destination_unit || item.unit || '') : '';
            hidden.dataset.factor = conv ? String(conv.factor || 1) : '';

            search.value = conv
                ? `${item.label} — receive ${formatQty(balance)} ${conv.destination_unit || item.unit || ''} max from bulk`
                : (isStockOutSelection()
                    ? `${item.label} — Available ${formatQty(balance)} ${item.unit || ''}`
                    : item.label);

            picker.classList.remove('is-open');
            hidden.dispatchEvent(new Event('change', {bubbles:true}));
        }

        function clearSelection(){
            hidden.value = '';
            hidden.dataset.cost = '';
            hidden.dataset.unit = '';
            hidden.dataset.available = '';
        }

        function renderList(){
            const term = search.value.trim().toLowerCase();
            const availableItems = allowedItemsForCurrentMovement();
            const matches = availableItems.filter(item => {
                if (!term) return true;
                return String(item.label || '').toLowerCase().includes(term);
            }).slice(0, 80);

            list.innerHTML = '';

            if (isStockOutSelection() && !currentStoreId()) {
                list.innerHTML = '<div class="item-search-empty">Select source store first.</div>';
                return;
            }

            if (!matches.length) {
                list.innerHTML = '<div class="item-search-empty">No matching item found.</div>';
                return;
            }

            matches.forEach(item => list.appendChild(makeItemOptionButton(item, term)));
        }

        search.addEventListener('focus', function(){
            closeAllItemPickers(picker);
            renderList();
            picker.classList.add('is-open');
            this.select();
        });

        search.addEventListener('input', function(){
            clearSelection();
            renderList();
            picker.classList.add('is-open');
        });

        list.addEventListener('mousedown', function(e){
            e.preventDefault();
            const btn = e.target.closest('.item-search-option');
            if (!btn) return;
            const item = allowedItemsForCurrentMovement().find(row => String(row.id) === String(btn.dataset.value));
            selectItem(item);
        });

        const selectedItem = selectedValue ? allowedItemsForCurrentMovement().find(item => String(item.id) === String(selectedValue)) : null;
        if (selectedItem) selectItem(selectedItem);

        return picker;
    }

    function updateLineAvailability(card){
        if (!card) return;
        const itemInput = card.querySelector('.item-select');
        const qtyInput = card.querySelector('.qty-input');
        const help = card.querySelector('.stock-help');
        if (!itemInput || !help) return;

        help.classList.remove('is-ok','is-empty','is-warn');

        if (!isStockOutSelection()) {
            if (qtyInput) qtyInput.removeAttribute('max');
            help.textContent = 'Stock availability restriction not applied for stock-in movements.';
            return;
        }

        if (!currentStoreId()) {
            if (qtyInput) qtyInput.removeAttribute('max');
            help.textContent = 'Select source store first to load available stock.';
            help.classList.add('is-warn');
            return;
        }

        const available = parseFloat(itemInput.dataset.available || '0') || 0;

        if (!itemInput.value) {
            if (qtyInput) qtyInput.removeAttribute('max');
            help.textContent = movementType && movementType.value === 'TRANSFER'
                ? 'Search the item to receive. If it has a conversion, the system will issue the bulk item automatically.'
                : 'Only items with stock in the selected source store are shown.';
            help.classList.add('is-warn');
            return;
        }

        if (qtyInput) qtyInput.setAttribute('max', String(available));

        const conv = conversionForDestination(itemInput.value);
        if (conv) {
            const enteredQty = qtyInput ? (parseFloat(qtyInput.value || '0') || available || conv.destination_qty || 0) : available;
            help.innerHTML = `<strong>Converted transfer:</strong> ${escapeHtml(conversionPreviewText(conv, enteredQty))}<br><span class="text-muted">Bulk available in source: ${escapeHtml(formatQty(sourceAvailableForConversion(conv)))} ${escapeHtml(conv.source_unit || '')}. Max receive: ${escapeHtml(formatQty(available))} ${escapeHtml(conv.destination_unit || itemInput.dataset.unit || '')}.</span>`;
            help.classList.add(available > 0 ? 'is-ok' : 'is-empty');
        } else {
            help.textContent = `Available in source store: ${formatQty(available)} ${itemInput.dataset.unit || ''}`;
            help.classList.add(available > 0 ? 'is-ok' : 'is-empty');
        }

        if (qtyInput && parseFloat(qtyInput.value || '0') > available) {
            qtyInput.value = available > 0 ? String(available) : '';
        }
    }

    function refreshItemDropdowns(){
        if (!movementLines) return;
        movementLines.querySelectorAll('.movement-line-card').forEach(card => {
            const oldInput = card.querySelector('.item-select');
            const oldValue = oldInput ? oldInput.value : '';
            const oldPicker = oldInput ? oldInput.closest('.native-item-picker') : null;
            const oldSelect = oldInput && oldInput.tagName === 'SELECT' ? oldInput : null;
            const target = oldPicker || oldSelect;
            if (!target || !target.parentNode) return;

            const stillAllowed = !oldValue || allowedItemsForCurrentMovement().some(item => String(item.id) === String(oldValue));
            const newPicker = buildItemSelect(stillAllowed ? oldValue : '');
            target.parentNode.replaceChild(newPicker, target);

            const costInput = card.querySelector('.cost-input');
            if (!stillAllowed && costInput) costInput.value = '';
            updateLineAvailability(card);
        });
        refreshTotals();
    }

    function addLine(){
        if (!movementLines) return;

        const card = document.createElement('div');
        card.className = 'movement-line-card';

        const top = document.createElement('div');
        top.className = 'd-flex justify-content-between align-items-center mb-2';

        const title = document.createElement('strong');
        title.textContent = 'Line';

        const remove = document.createElement('button');
        remove.type = 'button';
        remove.className = 'btn btn-sm btn-outline-danger remove-line';
        remove.title = 'Remove line';
        remove.innerHTML = '<i class="bi bi-x-lg"></i>';

        top.appendChild(title);
        top.appendChild(remove);

        const row = document.createElement('div');
        row.className = 'row g-2';

        const itemCol = document.createElement('div');
        itemCol.className = 'col-md-6';
        itemCol.innerHTML = '<label class="form-label">Item to Move / Receive</label>';
        itemCol.appendChild(buildItemSelect(''));

        const itemHelp = document.createElement('div');
        itemHelp.className = 'stock-help small text-muted mt-1';
        itemHelp.textContent = 'For converted transfers, select the outlet item to receive; the source bulk item is deducted automatically.';
        itemCol.appendChild(itemHelp);

        const qtyCol = document.createElement('div');
        qtyCol.className = 'col-md-3';
        qtyCol.innerHTML = '<label class="form-label">Quantity</label><input type="number"     step="0.0001"    min="0.0001" name="qty[]" class="form-control qty-input" required>';

        const costCol = document.createElement('div');
        costCol.className = 'col-md-3';
        costCol.innerHTML = '<label class="form-label">Unit Cost</label><input type="number" step="0.0001" min="0" name="unit_cost[]" class="form-control cost-input">';

        row.appendChild(itemCol);
        row.appendChild(qtyCol);
        row.appendChild(costCol);

        card.appendChild(top);
        card.appendChild(row);
        movementLines.appendChild(card);

        renumberLines();
        refreshTotals();
    }

    function renumberLines(){
        if (!movementLines) return;
        [...movementLines.children].forEach((card, index) => {
            const strong = card.querySelector('strong');
            if (strong) strong.textContent = 'Line ' + (index + 1);

            const removeBtn = card.querySelector('.remove-line');
            if (removeBtn) removeBtn.style.display = movementLines.children.length <= 1 ? 'none' : '';
        });
    }

    function refreshTotals(){
        if (!movementLines) return;

        let total = 0;
        let lines = 0;

        movementLines.querySelectorAll('.movement-line-card').forEach(card => {
            const qty = parseFloat(card.querySelector('.qty-input')?.value || '0') || 0;
            const cost = parseFloat(card.querySelector('.cost-input')?.value || '0') || 0;

            if (qty > 0) lines++;
            total += qty * cost;
        });

        if (lineCount) lineCount.textContent = String(lines || movementLines.children.length);
        if (estimatedValue) {
            estimatedValue.textContent = total.toLocaleString(undefined, {
                minimumFractionDigits: 2,
                maximumFractionDigits: 2
            });
        }
    }

    function autoFillCost(itemInput){
        const cost = itemInput ? itemInput.dataset.cost : '';
        const card = itemInput ? itemInput.closest('.movement-line-card') : null;
        const costInput = card ? card.querySelector('.cost-input') : null;

        if (costInput && cost && (!costInput.value || parseFloat(costInput.value) <= 0)) {
            costInput.value = cost;
        }
        updateLineAvailability(card);
    }

    document.addEventListener('mousedown', function(e){
        if (!e.target.closest('.native-item-picker')) closeAllItemPickers(null);
    });

    if (movementLines) {
        movementLines.addEventListener('change', function(e){
            if (e.target.classList.contains('item-select')) {
                autoFillCost(e.target);
                refreshTotals();
            }
        });

        movementLines.addEventListener('input', function(e){
            if (e.target.classList.contains('qty-input')) {
                const card = e.target.closest('.movement-line-card');
                if (card && isStockOutSelection()) {
                    const max = parseFloat(e.target.getAttribute('max') || '0') || 0;
                    const entered = parseFloat(e.target.value || '0') || 0;
                    if (max > 0 && entered > max) {
                        e.target.value = String(max);
                        const help = card.querySelector('.stock-help');
                        if (help) {
                            help.textContent = 'Quantity adjusted to available stock: ' + formatQty(max);
                            help.classList.remove('is-ok','is-empty');
                            help.classList.add('is-warn');
                        }
                    } else {
                        updateLineAvailability(card);
                    }
                }
            }
            refreshTotals();
        });

        movementLines.addEventListener('click', function(e){
            const btn = e.target.closest('.remove-line');
            if (!btn) return;

            const card = btn.closest('.movement-line-card');
            if (card && movementLines.children.length > 1) {
                card.remove();
                renumberLines();
                refreshTotals();
            }
        });
    }

    document.querySelectorAll('.batch-toggle').forEach(btn => {
        btn.addEventListener('click', function(){
            const targetId = this.getAttribute('data-target');
            const row = targetId ? document.getElementById(targetId) : null;
            if (!row) return;

            const isHidden = row.style.display === 'none' || row.style.display === '';
            row.style.display = isHidden ? 'table-row' : 'none';
            this.classList.toggle('is-open', isHidden);
        });
    });

    if (movementType) movementType.addEventListener('change', function(){
        toggleDestination();
        refreshItemDropdowns();
    });
    if (sourceStore) sourceStore.addEventListener('change', refreshItemDropdowns);
    if (destinationType) destinationType.addEventListener('change', toggleDestination);
    if (addLineBtn) addLineBtn.addEventListener('click', addLine);

    renumberLines();
    toggleDestination();
    refreshItemDropdowns();
    refreshTotals();
});
</script>

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