<?php
// transfer_booking_charges.php
// Transfer selected charge transactions from one booking to another booking.

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

$pageTitle = 'Transfer Booking Charges';

if (!function_exists('h')) {
    function h($value): string
    {
        return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
    }
}

if (!function_exists('tbc_money')) {
    function tbc_money($amount): string
    {
        return number_format((float)$amount, 2);
    }
}

if (!function_exists('tbc_date')) {
    function tbc_date($value, string $format = 'd M Y'): string
    {
        if (!$value) return '';
        $ts = strtotime((string)$value);
        return $ts ? date($format, $ts) : (string)$value;
    }
}

if (!function_exists('tbc_table_exists')) {
    function tbc_table_exists(PDO $pdo, string $table): bool
    {
        static $cache = [];
        $key = strtolower($table);
        if (array_key_exists($key, $cache)) return $cache[$key];

        try {
            $stmt = $pdo->prepare("\n                SELECT COUNT(*)\n                FROM INFORMATION_SCHEMA.TABLES\n                WHERE TABLE_SCHEMA = DATABASE()\n                  AND TABLE_NAME = :table_name\n            ");
            $stmt->execute([':table_name' => $table]);
            $cache[$key] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) {
            $cache[$key] = false;
        }
        return $cache[$key];
    }
}

if (!function_exists('tbc_column_exists')) {
    function tbc_column_exists(PDO $pdo, string $table, string $column): bool
    {
        static $cache = [];
        $key = strtolower($table . '.' . $column);
        if (array_key_exists($key, $cache)) return $cache[$key];

        try {
            $stmt = $pdo->prepare("\n                SELECT COUNT(*)\n                FROM INFORMATION_SCHEMA.COLUMNS\n                WHERE TABLE_SCHEMA = DATABASE()\n                  AND TABLE_NAME = :table_name\n                  AND COLUMN_NAME = :column_name\n            ");
            $stmt->execute([
                ':table_name' => $table,
                ':column_name' => $column,
            ]);
            $cache[$key] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) {
            $cache[$key] = false;
        }
        return $cache[$key];
    }
}

if (!function_exists('tbc_column_max_length')) {
    function tbc_column_max_length(PDO $pdo, string $table, string $column, int $fallback = 250): int
    {
        static $cache = [];
        $key = strtolower($table . '.' . $column);
        if (array_key_exists($key, $cache)) return $cache[$key];

        try {
            $stmt = $pdo->prepare("\n                SELECT CHARACTER_MAXIMUM_LENGTH, DATA_TYPE\n                FROM INFORMATION_SCHEMA.COLUMNS\n                WHERE TABLE_SCHEMA = DATABASE()\n                  AND TABLE_NAME = :table_name\n                  AND COLUMN_NAME = :column_name\n                LIMIT 1\n            ");
            $stmt->execute([
                ':table_name' => $table,
                ':column_name' => $column,
            ]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $len = $row ? (int)($row['CHARACTER_MAXIMUM_LENGTH'] ?? 0) : 0;
            $dataType = $row ? strtolower((string)($row['DATA_TYPE'] ?? '')) : '';
            // TEXT/MEDIUMTEXT/LONGTEXT columns report NULL for CHARACTER_MAXIMUM_LENGTH but aren't actually length-limited in the way VARCHAR is.
            if ($len <= 0 && in_array($dataType, ['text', 'mediumtext', 'longtext'], true)) {
                $len = 65000; // effectively unbounded for our purposes
            }
            $cache[$key] = $len > 0 ? $len : $fallback;
        } catch (Throwable $e) {
            $cache[$key] = $fallback;
        }
        return $cache[$key];
    }
}

if (!function_exists('tbc_current_user_id')) {
    function tbc_current_user_id(): ?int
    {
        foreach (['user_id', 'consultant_id', 'login_user_id', 'ss_user_id', 'id', 'uid'] as $key) {
            if (isset($_SESSION[$key]) && (int)$_SESSION[$key] > 0) {
                return (int)$_SESSION[$key];
            }
        }
        return null;
    }
}

if (!function_exists('tbc_safe_return_url')) {
    function tbc_safe_return_url(string $returnUrl): string
    {
        $returnUrl = trim($returnUrl);
        if ($returnUrl === '') return '/rooms/modules/calendar/calendar.php';
        if (preg_match('/^https?:\/\//i', $returnUrl)) return '/rooms/modules/calendar/calendar.php';
        if ($returnUrl[0] !== '/') return '/rooms/modules/calendar/calendar.php';
        return $returnUrl;
    }
}

if (!function_exists('tbc_next_folio_no')) {
    function tbc_next_folio_no(PDO $pdo, int $propertyId = 0): string
    {
        $prefix = 'FOL';
        if ($propertyId > 0 && tbc_table_exists($pdo, 'properties') && tbc_column_exists($pdo, 'properties', 'code')) {
            try {
                $stmt = $pdo->prepare("SELECT code FROM properties WHERE id = :id LIMIT 1");
                $stmt->execute([':id' => $propertyId]);
                $code = strtoupper(trim((string)$stmt->fetchColumn()));
                if ($code !== '') $prefix = 'FOL-' . $code;
            } catch (Throwable $e) {}
        }

        do {
            $folioNo = $prefix . '-' . date('YmdHis') . '-' . random_int(100, 999);
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM folios WHERE folio_no = :folio_no");
            $stmt->execute([':folio_no' => $folioNo]);
        } while ((int)$stmt->fetchColumn() > 0);

        return $folioNo;
    }
}

if (!function_exists('tbc_fetch_order')) {
    function tbc_fetch_order(PDO $pdo, int $orderId): ?array
    {
        if ($orderId <= 0) return null;

        $stmt = $pdo->prepare("\n            SELECT\n                o.*,\n                g.firstname,\n                g.lastname,\n                p.name AS property_name,\n                p.code AS property_code,\n                a.firstname AS agent_firstname,\n                a.lastname AS agent_lastname\n            FROM orders o\n            LEFT JOIN guests g ON g.id = o.guest_id\n            LEFT JOIN properties p ON p.id = o.property_id\n            LEFT JOIN agents a ON a.id = o.agent_id\n            WHERE o.id = :id\n            LIMIT 1\n        ");
        $stmt->execute([':id' => $orderId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return $row ?: null;
    }
}

if (!function_exists('tbc_guest_name')) {
    function tbc_guest_name(array $order): string
    {
        $name = trim((string)($order['firstname'] ?? '') . ' ' . (string)($order['lastname'] ?? ''));
        return $name !== '' ? $name : ('Booking #' . (int)($order['id'] ?? 0));
    }
}

if (!function_exists('tbc_agent_name')) {
    function tbc_agent_name(array $order): string
    {
        $name = trim((string)($order['agent_firstname'] ?? '') . ' ' . (string)($order['agent_lastname'] ?? ''));
        return $name !== '' ? $name : 'Direct / No agent';
    }
}

if (!function_exists('tbc_order_label')) {
    function tbc_order_label(array $order): string
    {
        $ref = trim((string)($order['order_no'] ?? ''));
        return ($ref !== '' ? $ref : ('Booking #' . (int)($order['id'] ?? 0))) . ' - ' . tbc_guest_name($order);
    }
}

if (!function_exists('tbc_get_or_create_master_folio')) {
    function tbc_get_or_create_master_folio(PDO $pdo, array $order): int
    {
        $orderId = (int)($order['id'] ?? 0);
        if ($orderId <= 0) throw new RuntimeException('Invalid destination booking.');

        $stmt = $pdo->prepare("\n            SELECT id\n            FROM folios\n            WHERE order_id = :order_id\n              AND LOWER(COALESCE(folio_type, '')) = 'master'\n            ORDER BY id ASC\n            LIMIT 1\n        ");
        $stmt->execute([':order_id' => $orderId]);
        $folioId = (int)($stmt->fetchColumn() ?: 0);
        if ($folioId > 0) return $folioId;

        $propertyId = (int)($order['property_id'] ?? 0);
        $folioNo = tbc_next_folio_no($pdo, $propertyId);
        $folioName = 'Master Folio - ' . tbc_order_label($order);

        $columns = ['property_id', 'order_id', 'folio_no', 'folio_name', 'folio_type', 'status', 'total_charges', 'total_payments', 'balance'];
        $values  = [':property_id', ':order_id', ':folio_no', ':folio_name', "'master'", '1', '0', '0', '0'];
        $params  = [
            ':property_id' => $propertyId,
            ':order_id'    => $orderId,
            ':folio_no'    => $folioNo,
            ':folio_name'  => $folioName,
        ];

        if (tbc_column_exists($pdo, 'folios', 'created_at')) {
            $columns[] = 'created_at';
            $values[] = 'NOW()';
        }
        if (tbc_column_exists($pdo, 'folios', 'created_by')) {
            $columns[] = 'created_by';
            $values[] = ':created_by';
            $params[':created_by'] = tbc_current_user_id();
        }

        $pdo->prepare('INSERT INTO folios (`' . implode('`,`', $columns) . '`) VALUES (' . implode(',', $values) . ')')
            ->execute($params);

        return (int)$pdo->lastInsertId();
    }
}

if (!function_exists('tbc_get_or_create_room_folio')) {
    /**
     * Get (or create) the ROOM folio for a specific rooming row within an order.
     * Used by "Move Accommodation to Room Account" so a guest can settle their
     * own room's accommodation separately from the master folio.
     */
    function tbc_get_or_create_room_folio(PDO $pdo, array $order, int $roomingId): int
    {
        $orderId = (int)($order['id'] ?? 0);
        if ($orderId <= 0 || $roomingId <= 0) throw new RuntimeException('Invalid room account.');

        $hasRoomingCol = tbc_column_exists($pdo, 'folios', 'rooming_id');
        if ($hasRoomingCol) {
            $stmt = $pdo->prepare("
                SELECT id FROM folios
                WHERE order_id = :order_id
                  AND LOWER(COALESCE(folio_type,'')) = 'room'
                  AND rooming_id = :rooming_id
                ORDER BY id ASC LIMIT 1
            ");
            $stmt->execute([':order_id' => $orderId, ':rooming_id' => $roomingId]);
            $existing = (int)($stmt->fetchColumn() ?: 0);
            if ($existing > 0) return $existing;
        }

        // Resolve the room number / room_id for a friendly folio name.
        $rm = $pdo->prepare("
            SELECT rmg.room_id, COALESCE(r.room_no, rmg.room_no) AS room_no
            FROM order_rooming rmg
            LEFT JOIN rooms r ON r.id = rmg.room_id
            WHERE rmg.id = :rid AND rmg.order_id = :oid LIMIT 1
        ");
        $rm->execute([':rid' => $roomingId, ':oid' => $orderId]);
        $rmRow = $rm->fetch(PDO::FETCH_ASSOC) ?: [];
        $roomNo = trim((string)($rmRow['room_no'] ?? ''));
        $roomId = (int)($rmRow['room_id'] ?? 0);

        $propertyId = (int)($order['property_id'] ?? 0);
        $folioNo = tbc_next_folio_no($pdo, $propertyId);
        $folioName = 'Room Folio' . ($roomNo !== '' ? ' - Room ' . $roomNo : '') . ' - ' . tbc_order_label($order);

        $columns = ['property_id', 'order_id', 'folio_no', 'folio_name', 'folio_type', 'status', 'total_charges', 'total_payments', 'balance'];
        $values  = [':property_id', ':order_id', ':folio_no', ':folio_name', "'room'", '1', '0', '0', '0'];
        $params  = [
            ':property_id' => $propertyId,
            ':order_id'    => $orderId,
            ':folio_no'    => $folioNo,
            ':folio_name'  => $folioName,
        ];
        if ($hasRoomingCol) {
            $columns[] = 'rooming_id'; $values[] = ':rooming_id'; $params[':rooming_id'] = $roomingId;
        }
        if (tbc_column_exists($pdo, 'folios', 'room_id') && $roomId > 0) {
            $columns[] = 'room_id'; $values[] = ':room_id'; $params[':room_id'] = $roomId;
        }
        if (tbc_column_exists($pdo, 'folios', 'created_at')) { $columns[] = 'created_at'; $values[] = 'NOW()'; }
        if (tbc_column_exists($pdo, 'folios', 'created_by')) {
            $columns[] = 'created_by'; $values[] = ':created_by'; $params[':created_by'] = tbc_current_user_id();
        }

        $pdo->prepare('INSERT INTO folios (`' . implode('`,`', $columns) . '`) VALUES (' . implode(',', $values) . ')')
            ->execute($params);
        return (int)$pdo->lastInsertId();
    }
}

if (!function_exists('tbc_fetch_accommodation_charges')) {
    /**
     * Accommodation / room-charge transactions currently on the MASTER folio of
     * an order, one row per posting (typically per night). These are what "Move
     * Accommodation to Room Account" can move to a room folio.
     */
    function tbc_fetch_accommodation_charges(PDO $pdo, int $orderId): array
    {
        // Resolve the master folio id first so we only offer master-folio rows.
        $mf = $pdo->prepare("
            SELECT id FROM folios
            WHERE order_id = :oid AND LOWER(COALESCE(folio_type,'')) = 'master'
            ORDER BY id ASC LIMIT 1
        ");
        $mf->execute([':oid' => $orderId]);
        $masterId = (int)($mf->fetchColumn() ?: 0);
        if ($masterId <= 0) return [];

        $stmt = $pdo->prepare("
            SELECT ft.id, ft.folio_id, ft.tx_date, ft.tx_type, ft.description,
                   COALESCE(ft.debit,0) AS debit, ft.source_table
            FROM folio_transactions ft
            WHERE ft.order_id = :oid
              AND ft.folio_id = :master_id
              AND COALESCE(ft.is_voided,0) = 0
              AND COALESCE(ft.debit,0) > 0
              AND COALESCE(ft.credit,0) = 0
              AND (
                    LOWER(COALESCE(ft.tx_type,'')) IN ('room_charge','accommodation','accommodation_charge','room','nightly','room_night')
                    OR LOWER(COALESCE(ft.source_table,'')) = 'rel_orders_prices'
                    OR LOWER(COALESCE(ft.description,'')) LIKE 'accommodation%'
              )
            ORDER BY ft.tx_date ASC, ft.id ASC
        ");
        $stmt->execute([':oid' => $orderId, ':master_id' => $masterId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }
}


if (!function_exists('tbc_recalculate_folio')) {
    function tbc_recalculate_folio(PDO $pdo, int $folioId): void
    {
        if ($folioId <= 0) return;

        $stmt = $pdo->prepare("\n            SELECT\n                COALESCE(SUM(CASE\n                    WHEN COALESCE(is_voided, 0) = 0\n                     AND LOWER(COALESCE(tx_type, '')) NOT IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment','payment_void','void_payment','payment_reversal','reversal','refund','payment_refund')\n                     AND LOWER(COALESCE(source_table, '')) NOT IN ('payment','payments','receipt','receipts')\n                    THEN COALESCE(debit, 0) ELSE 0 END), 0) AS total_charges,\n\n                GREATEST(0, COALESCE(SUM(CASE\n                    WHEN COALESCE(is_voided, 0) = 0\n                     AND (LOWER(COALESCE(tx_type, '')) IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment')\n                          OR LOWER(COALESCE(source_table, '')) IN ('payment','payments','receipt','receipts'))\n                     AND COALESCE(credit, 0) > 0\n                    THEN COALESCE(credit, 0)\n\n                    WHEN COALESCE(is_voided, 0) = 0\n                     AND (LOWER(COALESCE(tx_type, '')) IN ('payment_void','void_payment','payment_reversal','reversal','refund','payment_refund')\n                          OR LOWER(COALESCE(description, '')) LIKE '%void%'\n                          OR LOWER(COALESCE(description, '')) LIKE '%reversal%'\n                          OR LOWER(COALESCE(description, '')) LIKE '%refund%')\n                     AND COALESCE(debit, 0) > 0\n                    THEN -1 * COALESCE(debit, 0)\n\n                    ELSE 0 END), 0)) AS total_payments\n            FROM folio_transactions\n            WHERE folio_id = :folio_id\n        ");
        $stmt->execute([':folio_id' => $folioId]);
        $totals = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];

        $charges = round((float)($totals['total_charges'] ?? 0), 2);
        $payments = round((float)($totals['total_payments'] ?? 0), 2);
        $balance = round($charges - $payments, 2);

        $set = ['total_charges = :charges', 'total_payments = :payments', 'balance = :balance'];
        $params = [':charges' => $charges, ':payments' => $payments, ':balance' => $balance, ':id' => $folioId];

        if (tbc_column_exists($pdo, 'folios', 'updated_at')) $set[] = 'updated_at = NOW()';
        if (tbc_column_exists($pdo, 'folios', 'updated_by')) {
            $set[] = 'updated_by = :updated_by';
            $params[':updated_by'] = tbc_current_user_id();
        }

        $pdo->prepare('UPDATE folios SET ' . implode(', ', $set) . ' WHERE id = :id')->execute($params);
    }
}

if (!function_exists('tbc_recalculate_order_folios')) {
    function tbc_recalculate_order_folios(PDO $pdo, int $orderId): void
    {
        $stmt = $pdo->prepare("SELECT id FROM folios WHERE order_id = :order_id");
        $stmt->execute([':order_id' => $orderId]);
        foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $folioId) {
            tbc_recalculate_folio($pdo, (int)$folioId);
        }
    }
}

if (!function_exists('tbc_log_order_action')) {
    function tbc_log_order_action(PDO $pdo, int $orderId, string $action, string $notes): void
    {
        if (!tbc_table_exists($pdo, 'order_update_logs')) return;

        try {
            $pdo->prepare("\n                INSERT INTO order_update_logs (order_id, user_id, action, notes, created_at)\n                VALUES (:order_id, :user_id, :action, :notes, NOW())\n            ")->execute([
                ':order_id' => $orderId,
                ':user_id'  => tbc_current_user_id(),
                ':action'   => $action,
                ':notes'    => $notes,
            ]);
        } catch (Throwable $e) {}
    }
}

if (!function_exists('tbc_fetch_transferable_charges')) {
    function tbc_fetch_transferable_charges(PDO $pdo, int $sourceOrderId): array
    {
        $stmt = $pdo->prepare("\n            SELECT\n                ft.id,\n                ft.folio_id,\n                ft.order_id,\n                ft.tx_date,\n                ft.tx_type,\n                ft.description,\n                COALESCE(ft.debit, 0) AS debit,\n                COALESCE(ft.credit, 0) AS credit,\n                ft.source_table,\n                ft.source_id,\n                f.folio_no,\n                f.folio_name\n            FROM folio_transactions ft\n            LEFT JOIN folios f ON f.id = ft.folio_id\n            WHERE ft.order_id = :order_id\n              AND COALESCE(ft.is_voided, 0) = 0\n              AND COALESCE(ft.debit, 0) > 0\n              AND COALESCE(ft.credit, 0) = 0\n              AND LOWER(COALESCE(ft.tx_type, '')) NOT IN (\n                    'payment','receipt','deposit','payment_received','folio_payment','guest_payment',\n                    'payment_void','void_payment','payment_reversal','reversal','refund','payment_refund'\n              )\n              AND LOWER(COALESCE(ft.source_table, '')) NOT IN ('payment','payments','receipt','receipts')\n            ORDER BY ft.tx_date ASC, ft.id ASC\n        ");
        $stmt->execute([':order_id' => $sourceOrderId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

if (!function_exists('tbc_search_destination_bookings')) {
    function tbc_search_destination_bookings(PDO $pdo, string $q, int $sourceOrderId, int $limit = 20): array
    {
        $q = trim($q);
        if ($q === '') return [];

        $like = '%' . $q . '%';
        $stmt = $pdo->prepare("\n            SELECT\n                o.id,\n                o.order_no,\n                o.check_in,\n                o.check_out,\n                o.status,\n                o.totalamount,\n                g.firstname,\n                g.lastname,\n                p.name AS property_name,\n                p.code AS property_code,\n                a.firstname AS agent_firstname,\n                a.lastname AS agent_lastname,\n                COALESCE(fs.balance, 0) AS balance\n            FROM orders o\n            LEFT JOIN guests g ON g.id = o.guest_id\n            LEFT JOIN properties p ON p.id = o.property_id\n            LEFT JOIN agents a ON a.id = o.agent_id\n            LEFT JOIN (\n                SELECT order_id, COALESCE(SUM(balance), 0) AS balance\n                FROM folios\n                GROUP BY order_id\n            ) fs ON fs.order_id = o.id\n            WHERE o.id <> :source_order_id\n              AND COALESCE(o.status, 1) <> 0\n              AND (\n                    CAST(o.id AS CHAR) LIKE :q1\n                 OR o.order_no LIKE :q2\n                 OR CONCAT(COALESCE(g.firstname,''), ' ', COALESCE(g.lastname,'')) LIKE :q3\n                 OR CONCAT(COALESCE(a.firstname,''), ' ', COALESCE(a.lastname,'')) LIKE :q4\n                 OR p.name LIKE :q5\n                 OR p.code LIKE :q6\n              )\n            ORDER BY o.check_in DESC, o.id DESC\n            LIMIT " . max(1, min(50, $limit)) . "\n        ");
        $stmt->execute([
            ':source_order_id' => $sourceOrderId,
            ':q1' => $like,
            ':q2' => $like,
            ':q3' => $like,
            ':q4' => $like,
            ':q5' => $like,
            ':q6' => $like,
        ]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

$sourceOrderId = (int)(
    $_GET['source_id']
    ?? $_GET['from_order_id']
    ?? $_GET['order_id']
    ?? $_POST['source_id']
    ?? $_POST['from_order_id']
    ?? $_POST['order_id']
    ?? 0
);
$destinationOrderId = (int)($_GET['destination_id'] ?? $_POST['destination_id'] ?? 0);
$returnUrl = tbc_safe_return_url((string)($_GET['return'] ?? $_POST['return'] ?? '/rooms/modules/calendar/calendar.php'));
$search = trim((string)($_GET['q'] ?? ''));
$errors = [];
$success = '';

$sourceOrder = tbc_fetch_order($pdo, $sourceOrderId);
if (!$sourceOrder) {
    $errors[] = 'Source booking was not found. The transfer page now accepts from_order_id/source_id/order_id; please confirm the ID exists in orders.id.';
}

$destinationOrder = null;
if ($destinationOrderId > 0) {
    $destinationOrder = tbc_fetch_order($pdo, $destinationOrderId);
    if (!$destinationOrder) {
        $errors[] = 'Destination booking was not found.';
        $destinationOrderId = 0;
    }
    if ($destinationOrderId === $sourceOrderId) {
        $errors[] = 'Destination booking cannot be the same as the source booking.';
        $destinationOrder = null;
        $destinationOrderId = 0;
    }
}

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

        if (!$sourceOrder) throw new RuntimeException('Source booking was not found.');
        if (!$destinationOrder) throw new RuntimeException('Please select a destination booking.');

        $selectedIds = $_POST['transaction_ids'] ?? [];
        if (!is_array($selectedIds)) $selectedIds = [];
        $selectedIds = array_values(array_unique(array_filter(array_map('intval', $selectedIds), fn($v) => $v > 0)));
        if (!$selectedIds) throw new RuntimeException('Please tick at least one charge to transfer.');

        $availableCharges = tbc_fetch_transferable_charges($pdo, $sourceOrderId);
        $availableById = [];
        foreach ($availableCharges as $row) {
            $availableById[(int)$row['id']] = $row;
        }

        $validIds = [];
        $totalTransferred = 0.00;
        $sourceFolioIds = [];
        foreach ($selectedIds as $id) {
            if (!isset($availableById[$id])) {
                continue;
            }
            $validIds[] = $id;
            $totalTransferred += (float)$availableById[$id]['debit'];
            $sourceFolioIds[(int)$availableById[$id]['folio_id']] = (int)$availableById[$id]['folio_id'];
        }

        if (!$validIds) throw new RuntimeException('Selected charges are no longer available for transfer.');

        $pdo->beginTransaction();

        $destinationFolioId = tbc_get_or_create_master_folio($pdo, $destinationOrder);
        $destinationPropertyId = (int)($destinationOrder['property_id'] ?? 0);
        $userId = tbc_current_user_id();
        $transferNote = 'Transferred from ' . tbc_order_label($sourceOrder) . ' to ' . tbc_order_label($destinationOrder);

        /*
           Appending the transfer note onto an existing description can push the
           combined string past the column's actual length (folio_transactions.description
           is commonly VARCHAR and can already be close to full for charges that list
           several items). Wrapping in LEFT(..., max_length) guarantees the write never
           exceeds the column, instead of MySQL rejecting the whole update in strict mode.
        */
        $descriptionMaxLength = tbc_column_max_length($pdo, 'folio_transactions', 'description', 250);

        $set = [
            'order_id = :destination_order_id',
            'folio_id = :destination_folio_id',
            "description = LEFT(CONCAT(COALESCE(description, ''), ' [', :transfer_note, ']'), :description_max_length)",
        ];
        $params = [
            ':destination_order_id' => $destinationOrderId,
            ':destination_folio_id' => $destinationFolioId,
            ':transfer_note' => $transferNote,
            ':description_max_length' => $descriptionMaxLength,
            ':source_order_id' => $sourceOrderId,
        ];

        if (tbc_column_exists($pdo, 'folio_transactions', 'property_id')) {
            $set[] = 'property_id = :destination_property_id';
            $params[':destination_property_id'] = $destinationPropertyId;
        }
        if (tbc_column_exists($pdo, 'folio_transactions', 'updated_at')) {
            $set[] = 'updated_at = NOW()';
        }
        if (tbc_column_exists($pdo, 'folio_transactions', 'updated_by')) {
            $set[] = 'updated_by = :updated_by';
            $params[':updated_by'] = $userId;
        }

        $placeholders = [];
        foreach ($validIds as $idx => $id) {
            $ph = ':tx_' . $idx;
            $placeholders[] = $ph;
            $params[$ph] = $id;
        }

        $sql = "\n            UPDATE folio_transactions\n            SET " . implode(', ', $set) . "\n            WHERE order_id = :source_order_id\n              AND id IN (" . implode(',', $placeholders) . ")\n        ";
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);

        if ($stmt->rowCount() <= 0) {
            throw new RuntimeException('No charges were transferred. Please refresh and try again.');
        }

        foreach ($sourceFolioIds as $folioId) {
            tbc_recalculate_folio($pdo, $folioId);
        }
        tbc_recalculate_folio($pdo, $destinationFolioId);
        tbc_recalculate_order_folios($pdo, $sourceOrderId);
        tbc_recalculate_order_folios($pdo, $destinationOrderId);

        $notes = 'Transferred ' . count($validIds) . ' charge(s), total ' . tbc_money($totalTransferred) . '. ' . $transferNote;
        tbc_log_order_action($pdo, $sourceOrderId, 'transfer_charges_out', $notes);
        tbc_log_order_action($pdo, $destinationOrderId, 'transfer_charges_in', $notes);

        $pdo->commit();

        $separator = (strpos($returnUrl, '?') === false) ? '?' : '&';
        header('Location: ' . $returnUrl . $separator . 'transfer_done=1');
        exit;
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        $errors[] = $e->getMessage();
    }
}

$charges = $sourceOrder ? tbc_fetch_transferable_charges($pdo, $sourceOrderId) : [];
$destinationResults = ($sourceOrder && $search !== '') ? tbc_search_destination_bookings($pdo, $search, $sourceOrderId) : [];

/* =========================================================================
   MOVE ACCOMMODATION TO ROOM ACCOUNT
   Moves selected accommodation (room-charge) transactions from an order's
   MASTER folio to a specific ROOM folio - e.g. when a guest settles their own
   room's accommodation (first night, whole stay, or chosen nights).

   Reuses the same re-pointing model as the charge transfer: change the row's
   folio_id, then recalculate both folios so balances stay correct. Same order
   throughout, so order_id is unchanged.

   Accepts JSON responses (for the Folio Control Centre) or a redirect.
   POST: action=move_accommodation_to_room, order_id, rooming_id,
         transaction_ids[] (optional; if omitted, moves ALL accommodation).
   ========================================================================= */
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && ($_POST['action'] ?? '') === 'move_accommodation_to_room') {
    $wantsJson = (
        (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest')
        || (isset($_POST['as_json']) && (string)$_POST['as_json'] === '1')
    );
    $emit = function (bool $ok, string $message, array $extra = []) use ($wantsJson, $returnUrl) {
        if ($wantsJson) {
            header('Content-Type: application/json');
            echo json_encode(array_merge(['ok' => $ok, 'message' => $message], $extra));
            exit;
        }
        $sep = (strpos($returnUrl, '?') === false) ? '?' : '&';
        header('Location: ' . $returnUrl . $sep . ($ok ? 'move_accom_done=1' : 'move_accom_error=1'));
        exit;
    };

    try {
        if (function_exists('verify_csrf')) verify_csrf();

        $moveOrderId = (int)($_POST['order_id'] ?? 0);
        $roomingId   = (int)($_POST['rooming_id'] ?? 0);
        if ($moveOrderId <= 0 || $roomingId <= 0) {
            throw new RuntimeException('Missing booking or room account.');
        }

        // Load the order for folio helpers.
        $ordStmt = $pdo->prepare("SELECT * FROM orders WHERE id = :id LIMIT 1");
        $ordStmt->execute([':id' => $moveOrderId]);
        $moveOrder = $ordStmt->fetch(PDO::FETCH_ASSOC);
        if (!$moveOrder) throw new RuntimeException('Booking not found.');

        // Confirm the rooming row belongs to this order.
        $chk = $pdo->prepare("SELECT id FROM order_rooming WHERE id = :rid AND order_id = :oid LIMIT 1");
        $chk->execute([':rid' => $roomingId, ':oid' => $moveOrderId]);
        if (!(int)($chk->fetchColumn() ?: 0)) {
            throw new RuntimeException('That room does not belong to this booking.');
        }

        $accomCharges = tbc_fetch_accommodation_charges($pdo, $moveOrderId);
        if (!$accomCharges) {
            throw new RuntimeException('No accommodation charges are on the master folio to move.');
        }

        // Optional per-night selection; default to ALL accommodation.
        $selectedIds = $_POST['transaction_ids'] ?? [];
        if (!is_array($selectedIds)) $selectedIds = [];
        $selectedIds = array_values(array_unique(array_filter(array_map('intval', $selectedIds), fn($v) => $v > 0)));

        $byId = [];
        foreach ($accomCharges as $c) $byId[(int)$c['id']] = $c;

        $moveIds = [];
        $moveTotal = 0.0;
        $sourceFolioIds = [];
        if ($selectedIds) {
            foreach ($selectedIds as $id) {
                if (isset($byId[$id])) {
                    $moveIds[] = $id;
                    $moveTotal += (float)$byId[$id]['debit'];
                    $sourceFolioIds[(int)$byId[$id]['folio_id']] = (int)$byId[$id]['folio_id'];
                }
            }
        } else {
            foreach ($accomCharges as $c) {
                $moveIds[] = (int)$c['id'];
                $moveTotal += (float)$c['debit'];
                $sourceFolioIds[(int)$c['folio_id']] = (int)$c['folio_id'];
            }
        }
        if (!$moveIds) throw new RuntimeException('No matching accommodation charges to move.');

        $pdo->beginTransaction();

        $roomFolioId = tbc_get_or_create_room_folio($pdo, $moveOrder, $roomingId);
        $userId = tbc_current_user_id();
        $note = 'Moved to room account';
        $descMax = tbc_column_max_length($pdo, 'folio_transactions', 'description', 250);

        $set = [
            'folio_id = :room_folio_id',
            "description = LEFT(CONCAT(COALESCE(description,''), ' [', :note, ']'), :desc_max)",
        ];
        $params = [
            ':room_folio_id' => $roomFolioId,
            ':note' => $note,
            ':desc_max' => $descMax,
            ':order_id' => $moveOrderId,
        ];
        if (tbc_column_exists($pdo, 'folio_transactions', 'updated_at')) $set[] = 'updated_at = NOW()';
        if (tbc_column_exists($pdo, 'folio_transactions', 'updated_by')) {
            $set[] = 'updated_by = :updated_by'; $params[':updated_by'] = $userId;
        }

        $ph = [];
        foreach ($moveIds as $i => $id) { $k = ':m' . $i; $ph[] = $k; $params[$k] = $id; }

        $sql = "UPDATE folio_transactions SET " . implode(', ', $set)
             . " WHERE order_id = :order_id AND id IN (" . implode(',', $ph) . ")";
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        if ($stmt->rowCount() <= 0) throw new RuntimeException('Nothing was moved. Please refresh and try again.');

        foreach ($sourceFolioIds as $fid) tbc_recalculate_folio($pdo, $fid);
        tbc_recalculate_folio($pdo, $roomFolioId);
        tbc_recalculate_order_folios($pdo, $moveOrderId);

        tbc_log_order_action($pdo, $moveOrderId, 'move_accommodation_to_room',
            'Moved ' . count($moveIds) . ' accommodation charge(s), total ' . tbc_money($moveTotal) . ' to room folio #' . $roomFolioId . '.');

        $pdo->commit();

        $emit(true, 'Moved ' . count($moveIds) . ' accommodation charge(s), total ' . tbc_money($moveTotal) . ' to the room account.', [
            'room_folio_id' => $roomFolioId,
            'moved_count' => count($moveIds),
            'moved_total' => round($moveTotal, 2),
        ]);
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        $emit(false, $e->getMessage());
    }
}

/* Read-only endpoint: list accommodation charges available to move (for the
   Folio Control Centre picker). GET accommodation_charges=1&order_id=... */
if (isset($_GET['accommodation_charges']) && (string)$_GET['accommodation_charges'] === '1') {
    header('Content-Type: application/json');
    $oid = (int)($_GET['order_id'] ?? 0);
    if ($oid <= 0) { echo json_encode(['ok' => false, 'message' => 'Missing order.']); exit; }
    try {
        $rows = tbc_fetch_accommodation_charges($pdo, $oid);
        $out = array_map(function ($r) {
            return [
                'id' => (int)$r['id'],
                'date' => substr((string)($r['tx_date'] ?? ''), 0, 10),
                'description' => (string)($r['description'] ?? ''),
                'amount' => round((float)$r['debit'], 2),
            ];
        }, $rows);
        echo json_encode(['ok' => true, 'charges' => $out]);
    } catch (Throwable $e) {
        echo json_encode(['ok' => false, 'message' => $e->getMessage()]);
    }
    exit;
}

$moveAccomMode = (($_GET['mode'] ?? '') === 'move_accommodation');
$moveAccomRoomFolios = [];
$moveAccomCharges = [];
if ($moveAccomMode && $sourceOrder) {
    // Room folios for this order (destinations) with their rooming/room info.
    $rf = $pdo->prepare("
        SELECT f.id AS folio_id, f.folio_no, f.folio_name,
               " . (tbc_column_exists($pdo, 'folios', 'rooming_id') ? "f.rooming_id" : "0 AS rooming_id") . ",
               rmg.id AS rmg_id,
               COALESCE(r.room_no, rmg.room_no) AS room_no
        FROM order_rooming rmg
        LEFT JOIN rooms r ON r.id = rmg.room_id
        LEFT JOIN folios f ON f.order_id = rmg.order_id
             AND LOWER(COALESCE(f.folio_type,'')) = 'room'
             " . (tbc_column_exists($pdo, 'folios', 'rooming_id') ? "AND f.rooming_id = rmg.id" : "") . "
        WHERE rmg.order_id = :oid
        ORDER BY r.room_no ASC, rmg.room_no ASC, rmg.id ASC
    ");
    $rf->execute([':oid' => $sourceOrderId]);
    $moveAccomRoomFolios = $rf->fetchAll(PDO::FETCH_ASSOC) ?: [];
    $moveAccomCharges = tbc_fetch_accommodation_charges($pdo, $sourceOrderId);
}

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

<style>
.transfer-shell { max-width: 1280px; margin: 0 auto; }
.transfer-hero { border: 0; border-radius: 22px; overflow: hidden; box-shadow: 0 18px 45px rgba(15,23,42,.10); }
.transfer-hero .card-body { padding: 1.1rem 1.25rem; background: linear-gradient(135deg,#0f172a,#1d4ed8); color: #fff; }
.transfer-hero small { color: rgba(255,255,255,.72); }
.transfer-card { border: 1px solid #e5e7eb; border-radius: 18px; box-shadow: 0 12px 34px rgba(15,23,42,.06); }
.transfer-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; color: #64748b; font-weight: 800; margin-bottom: .2rem; }
.booking-box { border: 1px solid #e5e7eb; border-radius: 16px; padding: .85rem; background: #fff; height: 100%; }
.booking-box.source { border-left: 7px solid #2563eb; }
.booking-box.destination { border-left: 7px solid #16a34a; }
.booking-title { font-size: 1rem; font-weight: 900; color: #0f172a; }
.booking-sub { color: #64748b; font-size: .82rem; }
.charge-table th { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: #64748b; background: #f8fafc; }
.charge-table td { vertical-align: middle; font-size: .86rem; }
.amount-cell { font-weight: 900; color: #0f172a; white-space: nowrap; }
.destination-result { border: 1px solid #e5e7eb; border-radius: 14px; padding: .75rem; margin-bottom: .55rem; background: #fff; }
.destination-result:hover { background: #f8fafc; }
.sticky-transfer-footer { position: sticky; bottom: 0; background: rgba(255,255,255,.96); border-top: 1px solid #e5e7eb; padding: .9rem; backdrop-filter: blur(8px); z-index: 10; }
</style>

<div class="transfer-shell">
    <div class="transfer-hero card mb-3">
        <div class="card-body d-flex flex-wrap align-items-center justify-content-between gap-3">
            <div>
                <div class="text-uppercase fw-bold small mb-1">Hotel Folio Transfer</div>
                <h4 class="mb-1 fw-black">Transfer Booking Charges</h4>
                <small>Move selected charge lines from the source booking to a destination booking, then return to the calendar dashboard.</small>
            </div>
            <a class="btn btn-light" href="<?php echo h($returnUrl); ?>">
                <i class="bi bi-arrow-left me-2"></i>Back to Calendar
            </a>
        </div>
    </div>

    <?php if ($errors): ?>
        <div class="alert alert-danger">
            <strong>Could not continue:</strong>
            <ul class="mb-0 mt-2">
                <?php foreach ($errors as $error): ?>
                    <li><?php echo h($error); ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
    <?php endif; ?>

    <?php if ($moveAccomMode && $sourceOrder): ?>
        <?php
            $accomTotal = 0.0;
            foreach ($moveAccomCharges as $c) $accomTotal += (float)$c['debit'];
            // De-duplicate room folios (rows can repeat when a room has no folio yet).
            $roomOptions = [];
            foreach ($moveAccomRoomFolios as $rfRow) {
                $key = (int)($rfRow['rmg_id'] ?? 0);
                if ($key <= 0 || isset($roomOptions[$key])) continue;
                $roomOptions[$key] = $rfRow;
            }
        ?>
        <div class="transfer-card card mb-3">
            <div class="card-body">
                <h5 class="fw-bold mb-1"><i class="bi bi-box-arrow-in-down-right me-2"></i>Move Accommodation to Room Account</h5>
                <p class="text-muted small mb-3">
                    Move accommodation charges from the master folio to a specific room account,
                    e.g. when a guest settles their own room's accommodation. Pick the room, then
                    choose whole stay or specific nights.
                </p>

                <?php if (!$moveAccomCharges): ?>
                    <div class="alert alert-info mb-0">There are no accommodation charges on the master folio to move.</div>
                <?php elseif (!$roomOptions): ?>
                    <div class="alert alert-warning mb-0">This booking has no rooms to move accommodation to.</div>
                <?php else: ?>
                <form method="post">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="move_accommodation_to_room">
                    <input type="hidden" name="order_id" value="<?php echo (int)$sourceOrderId; ?>">

                    <div class="mb-3" style="max-width:520px;">
                        <label class="transfer-label d-block">Move to room</label>
                        <select name="rooming_id" class="form-select" required>
                            <option value="">— Select a room —</option>
                            <?php foreach ($roomOptions as $rmgId => $rfRow): ?>
                                <option value="<?php echo (int)$rmgId; ?>">
                                    Room <?php echo h($rfRow['room_no'] ?: ('#' . $rmgId)); ?><?php echo $rfRow['folio_no'] ? ' (' . h($rfRow['folio_no']) . ')' : ' (folio will be created)'; ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>

                    <div class="mb-2">
                        <label class="transfer-label d-block">Nights to move</label>
                        <div class="form-check">
                            <input class="form-check-input" type="radio" name="move_scope" id="moveAll" value="all" checked onchange="document.getElementById('accomNightsWrap').style.display='none';">
                            <label class="form-check-label" for="moveAll">Whole accommodation (<?php echo h(tbc_money($accomTotal)); ?>)</label>
                        </div>
                        <div class="form-check">
                            <input class="form-check-input" type="radio" name="move_scope" id="movePick" value="pick" onchange="document.getElementById('accomNightsWrap').style.display='block';">
                            <label class="form-check-label" for="movePick">Selected nights only</label>
                        </div>
                    </div>

                    <div id="accomNightsWrap" style="display:none;" class="mb-3">
                        <table class="table table-sm charge-table">
                            <thead><tr><th style="width:40px;"></th><th>Date</th><th>Description</th><th class="text-end">Amount</th></tr></thead>
                            <tbody>
                                <?php foreach ($moveAccomCharges as $c): ?>
                                <tr>
                                    <td><input class="form-check-input accom-night" type="checkbox" name="transaction_ids[]" value="<?php echo (int)$c['id']; ?>"></td>
                                    <td><?php echo h(substr((string)($c['tx_date'] ?? ''), 0, 10)); ?></td>
                                    <td><?php echo h($c['description'] ?? ''); ?></td>
                                    <td class="text-end amount-cell"><?php echo h(tbc_money((float)$c['debit'])); ?></td>
                                </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                        <div class="form-text">If none are ticked, the whole accommodation is moved.</div>
                    </div>

                    <div class="d-flex gap-2">
                        <button class="btn btn-success" onclick="return confirm('Move accommodation to the selected room account?');">
                            <i class="bi bi-check2-circle me-1"></i>Move Accommodation
                        </button>
                        <a class="btn btn-light" href="<?php echo h($returnUrl); ?>">Cancel</a>
                    </div>
                </form>
                <?php endif; ?>
            </div>
        </div>
    <?php endif; ?>

    <?php if ($sourceOrder && !$moveAccomMode): ?>
        <div class="row g-3 mb-3">
            <div class="col-lg-6">
                <div class="booking-box source">
                    <div class="transfer-label">Source Booking</div>
                    <div class="booking-title"><?php echo h(tbc_order_label($sourceOrder)); ?></div>
                    <div class="booking-sub">
                        <?php echo h(tbc_date($sourceOrder['check_in'] ?? '')); ?> → <?php echo h(tbc_date($sourceOrder['check_out'] ?? '')); ?>
                        • <?php echo h($sourceOrder['property_name'] ?? ''); ?>
                    </div>
                    <div class="booking-sub mt-1">
                        Agent: <?php echo h(tbc_agent_name($sourceOrder)); ?>
                        • Booking ID: <?php echo (int)$sourceOrderId; ?>
                    </div>
                </div>
            </div>

            <div class="col-lg-6">
                <div class="booking-box destination">
                    <div class="transfer-label">Destination Booking</div>
                    <?php if ($destinationOrder): ?>
                        <div class="booking-title"><?php echo h(tbc_order_label($destinationOrder)); ?></div>
                        <div class="booking-sub">
                            <?php echo h(tbc_date($destinationOrder['check_in'] ?? '')); ?> → <?php echo h(tbc_date($destinationOrder['check_out'] ?? '')); ?>
                            • <?php echo h($destinationOrder['property_name'] ?? ''); ?>
                        </div>
                        <div class="booking-sub mt-1">
                            Agent: <?php echo h(tbc_agent_name($destinationOrder)); ?>
                            • Booking ID: <?php echo (int)$destinationOrderId; ?>
                        </div>
                        <a class="btn btn-sm btn-outline-secondary mt-2" href="transfer_booking_charges.php?<?php echo h(http_build_query(['source_id'=>$sourceOrderId,'return'=>$returnUrl])); ?>">
                            Change Destination
                        </a>
                    <?php else: ?>
                        <div class="text-muted">Search and select the booking that should receive the selected charges.</div>
                    <?php endif; ?>
                </div>
            </div>
        </div>

        <?php if (!$destinationOrder): ?>
            <div class="card transfer-card mb-3">
                <div class="card-body">
                    <form method="get" class="row g-2 align-items-end">
                        <input type="hidden" name="source_id" value="<?php echo (int)$sourceOrderId; ?>">
            <input type="hidden" name="from_order_id" value="<?php echo (int)$sourceOrderId; ?>">
                        <input type="hidden" name="return" value="<?php echo h($returnUrl); ?>">
                        <div class="col-lg-10">
                            <label class="form-label fw-semibold">Search Destination Booking</label>
                            <input type="text" class="form-control" name="q" value="<?php echo h($search); ?>" placeholder="Search by booking ref, guest, agent, property or booking ID">
                        </div>
                        <div class="col-lg-2 d-grid">
                            <button class="btn btn-primary"><i class="bi bi-search me-2"></i>Search</button>
                        </div>
                    </form>

                    <?php if ($search !== ''): ?>
                        <div class="mt-3">
                            <?php if ($destinationResults): ?>
                                <?php foreach ($destinationResults as $dest): ?>
                                    <div class="destination-result d-flex flex-wrap justify-content-between align-items-center gap-3">
                                        <div>
                                            <div class="fw-bold"><?php echo h(tbc_order_label($dest)); ?></div>
                                            <div class="small text-muted">
                                                <?php echo h(tbc_date($dest['check_in'] ?? '')); ?> → <?php echo h(tbc_date($dest['check_out'] ?? '')); ?>
                                                • <?php echo h($dest['property_name'] ?? ''); ?>
                                                • Agent: <?php echo h(tbc_agent_name($dest)); ?>
                                                • Balance: <?php echo h(tbc_money($dest['balance'] ?? 0)); ?>
                                            </div>
                                        </div>
                                        <a class="btn btn-success btn-sm" href="transfer_booking_charges.php?<?php echo h(http_build_query(['source_id'=>$sourceOrderId,'destination_id'=>(int)$dest['id'],'q'=>$search,'return'=>$returnUrl])); ?>">
                                            Select Destination
                                        </a>
                                    </div>
                                <?php endforeach; ?>
                            <?php else: ?>
                                <div class="alert alert-warning mb-0">No destination bookings matched your search.</div>
                            <?php endif; ?>
                        </div>
                    <?php endif; ?>
                </div>
            </div>
        <?php endif; ?>

        <form method="post">
            <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
            <input type="hidden" name="action" value="transfer_charges">
            <input type="hidden" name="source_id" value="<?php echo (int)$sourceOrderId; ?>">
            <input type="hidden" name="from_order_id" value="<?php echo (int)$sourceOrderId; ?>">
            <input type="hidden" name="destination_id" value="<?php echo (int)$destinationOrderId; ?>">
            <input type="hidden" name="return" value="<?php echo h($returnUrl); ?>">

            <div class="card transfer-card">
                <div class="card-header bg-white border-0 pt-3 px-3">
                    <div class="d-flex flex-wrap justify-content-between align-items-center gap-2">
                        <div>
                            <h5 class="mb-1">Select Charges to Transfer</h5>
                            <div class="text-muted small">Only active debit charge lines are shown. Payments, receipts, refunds and voids are excluded.</div>
                        </div>
                        <?php if ($charges): ?>
                            <button type="button" class="btn btn-sm btn-outline-primary" onclick="document.querySelectorAll('.charge-check').forEach(c => c.checked = true); updateTransferTotal();">
                                Select All
                            </button>
                        <?php endif; ?>
                    </div>
                </div>

                <div class="card-body p-0">
                    <?php if ($charges): ?>
                        <div class="table-responsive">
                            <table class="table table-hover charge-table mb-0">
                                <thead>
                                    <tr>
                                        <th style="width:45px;"></th>
                                        <th>Date</th>
                                        <th>Folio</th>
                                        <th>Type</th>
                                        <th>Description</th>
                                        <th class="text-end">Amount</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach ($charges as $charge): ?>
                                        <tr>
                                            <td>
                                                <input class="form-check-input charge-check" type="checkbox" name="transaction_ids[]" value="<?php echo (int)$charge['id']; ?>" data-amount="<?php echo h((float)$charge['debit']); ?>" onchange="updateTransferTotal();">
                                            </td>
                                            <td><?php echo h(tbc_date($charge['tx_date'] ?? '', 'd M Y')); ?></td>
                                            <td>
                                                <div class="fw-semibold"><?php echo h($charge['folio_no'] ?? ('Folio #' . (int)$charge['folio_id'])); ?></div>
                                                <div class="small text-muted"><?php echo h($charge['folio_name'] ?? ''); ?></div>
                                            </td>
                                            <td><?php echo h($charge['tx_type'] ?? 'charge'); ?></td>
                                            <td><?php echo h($charge['description'] ?? ''); ?></td>
                                            <td class="text-end amount-cell"><?php echo h(tbc_money($charge['debit'] ?? 0)); ?></td>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                    <?php else: ?>
                        <div class="p-4 text-muted">No transferable charges found on this booking.</div>
                    <?php endif; ?>
                </div>

                <div class="sticky-transfer-footer d-flex flex-wrap align-items-center justify-content-between gap-3">
                    <div>
                        <div class="small text-muted">Selected Total</div>
                        <div class="h5 mb-0 fw-bold" id="selectedTransferTotal">0.00</div>
                    </div>
                    <div class="d-flex flex-wrap gap-2">
                        <a class="btn btn-outline-secondary" href="<?php echo h($returnUrl); ?>">Cancel</a>
                        <button class="btn btn-success" <?php echo (!$destinationOrder || !$charges) ? 'disabled' : ''; ?> onclick="return confirm('Transfer selected charges from the source booking to the destination booking?');">
                            <i class="bi bi-arrow-left-right me-2"></i>Transfer Selected Charges
                        </button>
                    </div>
                </div>
            </div>
        </form>
    <?php endif; ?>
</div>

<script>
function updateTransferTotal() {
    var total = 0;
    document.querySelectorAll('.charge-check:checked').forEach(function (box) {
        total += parseFloat(box.getAttribute('data-amount') || '0') || 0;
    });
    var el = document.getElementById('selectedTransferTotal');
    if (el) el.textContent = total.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
}
updateTransferTotal();
</script>

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