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

$pageTitle = 'Arrivals Today';

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('arrival_status_badge')) {
    function arrival_status_badge(string $status): string
    {
        switch ($status) {
            case 'checked_in':
                return '<span class="badge text-bg-success">Checked In</span>';
            case 'partial':
                return '<span class="badge text-bg-warning text-dark">Partial Check-In</span>';
            case 'no_show':
                return '<span class="badge text-bg-danger">No Show</span>';
            case 'cancelled':
            case 'canceled':
                return '<span class="badge text-bg-dark">Cancelled</span>';
            default:
                return '<span class="badge text-bg-secondary">Pending</span>';
        }
    }
}

if (!function_exists('arrivals_flash')) {
    function arrivals_flash(string $type, string $message): void
    {
        $_SESSION['arrivals_flash'][] = ['type' => $type, 'message' => $message];
    }
}

if (!function_exists('arrivals_get_flash')) {
    function arrivals_get_flash(): array
    {
        $items = $_SESSION['arrivals_flash'] ?? [];
        unset($_SESSION['arrivals_flash']);
        return is_array($items) ? $items : [];
    }
}

if (!function_exists('arrivals_current_user_id')) {
    function arrivals_current_user_id(): ?int
    {
        foreach (['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('arrivals_table_exists')) {
    function arrivals_table_exists(PDO $pdo, string $table): bool
    {
        static $cache = [];
        if (array_key_exists($table, $cache)) return $cache[$table];
        try {
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = :t");
            $stmt->execute([':t' => $table]);
            return $cache[$table] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) {
            return $cache[$table] = false;
        }
    }
}

if (!function_exists('arrivals_column_exists')) {
    function arrivals_column_exists(PDO $pdo, string $table, string $column): bool
    {
        static $cache = [];
        $key = $table . '.' . $column;
        if (array_key_exists($key, $cache)) return $cache[$key];
        try {
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :t AND column_name = :c");
            $stmt->execute([':t' => $table, ':c' => $column]);
            return $cache[$key] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) {
            return $cache[$key] = false;
        }
    }
}

if (!function_exists('arrivals_column_is_nullable')) {
    function arrivals_column_is_nullable(PDO $pdo, string $table, string $column): bool
    {
        try {
            $stmt = $pdo->prepare("SELECT IS_NULLABLE FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :t AND column_name = :c LIMIT 1");
            $stmt->execute([':t' => $table, ':c' => $column]);
            return strtoupper((string)($stmt->fetchColumn() ?: 'NO')) === 'YES';
        } catch (Throwable $e) {
            return false;
        }
    }
}

if (!function_exists('arrivals_safe_set_booking_status')) {
    function arrivals_safe_set_booking_status(PDO $pdo, string $statusValue, array &$sets, array &$params, string $paramName = ':booking_status'): void
    {
        // orders.status is numeric in this PMS. Workflow text belongs in booking_status only.
        arrivals_try_add_column($pdo, 'orders', 'booking_status', '`booking_status` VARCHAR(40) NULL AFTER `status`');
        if (arrivals_column_exists($pdo, 'orders', 'booking_status')) {
            $sets[] = "booking_status = {$paramName}";
            $params[$paramName] = $statusValue;
        }
    }
}

if (!function_exists('arrivals_try_add_column')) {
    function arrivals_try_add_column(PDO $pdo, string $table, string $column, string $definition): void
    {
        if (arrivals_column_exists($pdo, $table, $column)) return;
        try {
            $pdo->exec("ALTER TABLE `" . str_replace('`', '``', $table) . "` ADD COLUMN " . $definition);
        } catch (Throwable $e) {
            // Do not block operations if the DB user has no ALTER privilege.
        }
    }
}

if (!function_exists('arrivals_next_folio_no')) {
    function arrivals_next_folio_no(PDO $pdo, int $propertyId = 0): string
    {
        $prefix = 'FOL';
        if ($propertyId > 0 && arrivals_table_exists($pdo, 'properties') && arrivals_column_exists($pdo, 'properties', 'code')) {
            try {
                $stmt = $pdo->prepare("SELECT code FROM properties WHERE id = :id LIMIT 1");
                $stmt->execute([':id' => $propertyId]);
                $code = trim((string)($stmt->fetchColumn() ?: ''));
                if ($code !== '') $prefix = 'FOL-' . strtoupper($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('arrivals_get_or_create_master_folio')) {
    function arrivals_get_or_create_master_folio(PDO $pdo, int $orderId): int
    {
        $stmt = $pdo->prepare("SELECT id FROM folios WHERE order_id = :order_id AND folio_type = 'master' LIMIT 1");
        $stmt->execute([':order_id' => $orderId]);
        $folioId = (int)($stmt->fetchColumn() ?: 0);
        if ($folioId > 0) return $folioId;

        $stmt = $pdo->prepare("SELECT o.property_id, o.order_no, g.firstname, g.lastname FROM orders o LEFT JOIN guests g ON g.id = o.guest_id WHERE o.id = :id LIMIT 1");
        $stmt->execute([':id' => $orderId]);
        $order = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$order) throw new RuntimeException('Booking not found while creating master folio.');

        $propertyId = (int)($order['property_id'] ?? 0);
        $guestName = trim(($order['firstname'] ?? '') . ' ' . ($order['lastname'] ?? ''));
        if ($guestName === '') $guestName = 'Guest';
        $folioNo = arrivals_next_folio_no($pdo, $propertyId);
        $folioName = 'Master Folio - ' . ($order['order_no'] ?: ('Booking #' . $orderId)) . ' - ' . $guestName;

        $stmt = $pdo->prepare("
            INSERT INTO folios
            (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)
        ");
        $stmt->execute([
            ':property_id' => $propertyId,
            ':order_id' => $orderId,
            ':folio_no' => $folioNo,
            ':folio_name' => $folioName,
        ]);
        return (int)$pdo->lastInsertId();
    }
}

if (!function_exists('arrivals_recalculate_folio_totals')) {
    function arrivals_recalculate_folio_totals(PDO $pdo, int $folioId): void
    {
        $stmt = $pdo->prepare("
            SELECT
                COALESCE(SUM(CASE
                    WHEN COALESCE(is_voided,0)=0
                     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')
                     AND LOWER(COALESCE(source_table,'')) NOT IN ('payment','payments','receipt','receipts')
                    THEN COALESCE(debit,0) ELSE 0 END),0) AS charges,
                GREATEST(0, COALESCE(SUM(CASE
                    WHEN COALESCE(is_voided,0)=0
                     AND (LOWER(COALESCE(tx_type,'')) IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment') OR LOWER(COALESCE(source_table,'')) IN ('payment','payments','receipt','receipts'))
                     AND COALESCE(credit,0)>0 THEN COALESCE(credit,0)
                    WHEN COALESCE(is_voided,0)=0
                     AND (LOWER(COALESCE(tx_type,'')) IN ('payment_void','void_payment','payment_reversal','reversal','refund','payment_refund') OR LOWER(COALESCE(description,'')) LIKE '%void%' OR LOWER(COALESCE(description,'')) LIKE '%reversal%' OR LOWER(COALESCE(description,'')) LIKE '%refund%')
                     AND COALESCE(debit,0)>0 THEN -1 * COALESCE(debit,0)
                    ELSE 0 END),0)) AS payments
            FROM folio_transactions
            WHERE folio_id = :folio_id
        ");
        $stmt->execute([':folio_id' => $folioId]);
        $totals = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
        $charges = round((float)($totals['charges'] ?? 0), 2);
        $payments = round((float)($totals['payments'] ?? 0), 2);
        $balance = round($charges - $payments, 2);
        $pdo->prepare("UPDATE folios SET total_charges=:c,total_payments=:p,balance=:b,updated_at=NOW() WHERE id=:id")
            ->execute([':c'=>$charges, ':p'=>$payments, ':b'=>$balance, ':id'=>$folioId]);
    }
}

if (!function_exists('arrivals_sync_order_payment_status')) {
    function arrivals_sync_order_payment_status(PDO $pdo, int $orderId): void
    {
        if (!arrivals_column_exists($pdo, 'orders', 'payment_status')) return;
        $stmt = $pdo->prepare("SELECT COALESCE(SUM(total_payments),0) payments, COALESCE(SUM(balance),0) balance FROM folios WHERE order_id=:id");
        $stmt->execute([':id'=>$orderId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
        $payments = (float)($row['payments'] ?? 0);
        $balance = (float)($row['balance'] ?? 0);
        $status = $payments <= 0.00001 ? 0 : ($balance <= 0.00001 ? 2 : 1);
        try {
            $pdo->prepare("UPDATE orders SET payment_status=:s WHERE id=:id")->execute([':s'=>$status, ':id'=>$orderId]);
        } catch (Throwable $e) {}
    }
}

if (!function_exists('arrivals_insert_folio_transaction')) {
    function arrivals_insert_folio_transaction(PDO $pdo, array $order, int $folioId, string $txType, string $description, float $debit, float $credit, string $txDate): int
    {
        if (!arrivals_table_exists($pdo, 'folio_transactions')) {
            throw new RuntimeException('Cannot post no-show accounting transaction because folio_transactions table was not found.');
        }
        $orderId = (int)($order['id'] ?? 0);
        $propertyId = (int)($order['property_id'] ?? 0);

        $columns = ['folio_id','order_id','tx_date','tx_type','description','debit','credit','source_table','source_id'];
        $values  = [':folio_id',':order_id',':tx_date',':tx_type',':description',':debit',':credit',':source_table',':source_id'];
        $params = [
            ':folio_id' => $folioId,
            ':order_id' => $orderId,
            ':tx_date' => $txDate . ' 00:00:00',
            ':tx_type' => $txType,
            ':description' => $description,
            ':debit' => round(max(0, $debit), 2),
            ':credit' => round(max(0, $credit), 2),
            ':source_table' => 'orders',
            ':source_id' => $orderId,
        ];

        if (arrivals_column_exists($pdo, 'folio_transactions', 'property_id')) {
            array_unshift($columns, 'property_id');
            array_unshift($values, ':property_id');
            $params[':property_id'] = $propertyId;
        }
        if (arrivals_column_exists($pdo, 'folio_transactions', 'created_at')) {
            $columns[] = 'created_at';
            $values[] = 'NOW()';
        }
        if (arrivals_column_exists($pdo, 'folio_transactions', 'created_by')) {
            $columns[] = 'created_by';
            $values[] = ':created_by';
            $params[':created_by'] = arrivals_current_user_id();
        }

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

if (!function_exists('arrivals_live_order_balance')) {
    function arrivals_live_order_balance(PDO $pdo, int $orderId): float
    {
        $stmt = $pdo->prepare("SELECT COALESCE(SUM(COALESCE(debit,0)-COALESCE(credit,0)),0) FROM folio_transactions WHERE order_id=:order_id AND COALESCE(is_voided,0)=0");
        $stmt->execute([':order_id' => $orderId]);
        return round((float)$stmt->fetchColumn(), 2);
    }
}

if (!function_exists('arrivals_recalculate_order_folios')) {
    function arrivals_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) {
            arrivals_recalculate_folio_totals($pdo, (int)$folioId);
        }
        arrivals_sync_order_payment_status($pdo, $orderId);
    }
}

if (!function_exists('arrivals_apply_no_show_policy_to_folio')) {
    function arrivals_apply_no_show_policy_to_folio(PDO $pdo, array $order, string $policyAction, float $requestedAdjustment, float $policyCharge, string $reason, string $txDate): array
    {
        $orderId = (int)($order['id'] ?? 0);
        $folioId = arrivals_get_or_create_master_folio($pdo, $orderId);
        $originalBalance = arrivals_live_order_balance($pdo, $orderId);
        $requestedAdjustment = round(max(0, $requestedAdjustment), 2);
        $policyCharge = round(max(0, $policyCharge), 2);
        $adjustmentAmount = 0.00;
        $postedCharge = 0.00;
        $bookingLabel = (string)($order['order_no'] ?: ('Booking #' . $orderId));
        $reasonSuffix = trim($reason) !== '' ? ' | ' . trim($reason) : '';

        if ($policyAction === 'keep_balance') {
            // Keep the existing folio as-is. No new financial transaction is posted.
        } elseif ($policyAction === 'waive_all') {
            $adjustmentAmount = max(0, $originalBalance);
        } elseif ($policyAction === 'waive_and_charge_policy') {
            $adjustmentAmount = min(max(0, $originalBalance), $requestedAdjustment);
            $postedCharge = $policyCharge;
        } else {
            throw new RuntimeException('Invalid no-show accounting option selected.');
        }

        if ($adjustmentAmount > 0.00001) {
            arrivals_insert_folio_transaction(
                $pdo,
                $order,
                $folioId,
                'no_show_adjustment',
                'No Show Cancellation Adjustment - ' . $bookingLabel . $reasonSuffix,
                0,
                $adjustmentAmount,
                $txDate
            );
        }

        if ($postedCharge > 0.00001) {
            arrivals_insert_folio_transaction(
                $pdo,
                $order,
                $folioId,
                'no_show_policy_charge',
                'No Show Policy Charge - ' . $bookingLabel . $reasonSuffix,
                $postedCharge,
                0,
                $txDate
            );
        }

        arrivals_recalculate_folio_totals($pdo, $folioId);
        arrivals_recalculate_order_folios($pdo, $orderId);

        return [
            'folio_id' => $folioId,
            'original_balance' => round($originalBalance, 2),
            'adjustment_amount' => round($adjustmentAmount, 2),
            'policy_charge' => round($postedCharge, 2),
            'final_balance' => arrivals_live_order_balance($pdo, $orderId),
        ];
    }
}

if (!function_exists('arrivals_release_no_show_rooms')) {
    function arrivals_release_no_show_rooms(PDO $pdo, int $orderId, string $reason = ''): void
    {
        arrivals_try_add_column($pdo, 'order_rooming', 'released_status', '`released_status` TINYINT(1) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'order_rooming', 'released_at', '`released_at` DATETIME NULL');
        arrivals_try_add_column($pdo, 'order_rooming', 'release_reason', '`release_reason` VARCHAR(255) NULL');

        $roomIds = [];
        try {
            $stmt = $pdo->prepare("SELECT DISTINCT room_id FROM order_rooming WHERE order_id=:id AND room_id IS NOT NULL AND room_id > 0");
            $stmt->execute([':id' => $orderId]);
            foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $rid) {
                $rid = (int)$rid;
                if ($rid > 0) $roomIds[$rid] = $rid;
            }
        } catch (Throwable $e) {}

        $updates = [];
        $params = [':id' => $orderId];

        if (arrivals_column_exists($pdo, 'order_rooming', 'room_id') && arrivals_column_is_nullable($pdo, 'order_rooming', 'room_id')) {
            $updates[] = 'room_id = NULL';
        }
        if (arrivals_column_exists($pdo, 'order_rooming', 'room_no') && arrivals_column_is_nullable($pdo, 'order_rooming', 'room_no')) {
            $updates[] = 'room_no = NULL';
        }
        if (arrivals_column_exists($pdo, 'order_rooming', 'checked_in_status')) $updates[] = 'checked_in_status = 0';
        if (arrivals_column_exists($pdo, 'order_rooming', 'checked_out_status')) $updates[] = 'checked_out_status = 1';
        if (arrivals_column_exists($pdo, 'order_rooming', 'released_status')) $updates[] = 'released_status = 1';
        if (arrivals_column_exists($pdo, 'order_rooming', 'released_at')) $updates[] = 'released_at = NOW()';
        if (arrivals_column_exists($pdo, 'order_rooming', 'release_reason')) { $updates[] = 'release_reason = :release_reason'; $params[':release_reason'] = $reason !== '' ? $reason : 'Released due to no-show'; }
        if (arrivals_column_exists($pdo, 'order_rooming', 'check_in') && arrivals_column_exists($pdo, 'order_rooming', 'check_out')) $updates[] = 'check_out = check_in';
        if (arrivals_column_exists($pdo, 'order_rooming', 'updated_at')) $updates[] = 'updated_at = NOW()';

        if ($updates) {
            $pdo->prepare('UPDATE order_rooming SET ' . implode(', ', $updates) . ' WHERE order_id=:id')->execute($params);
        }

        if ($roomIds && arrivals_table_exists($pdo, 'rooms')) {
            foreach ($roomIds as $roomId) {
                $roomSet = [];
                if (arrivals_column_exists($pdo, 'rooms', 'status')) $roomSet[] = "status='available'";
                if (arrivals_column_exists($pdo, 'rooms', 'housekeeping_status')) $roomSet[] = "housekeeping_status='clean'";
                if (arrivals_column_exists($pdo, 'rooms', 'updated_at')) $roomSet[] = 'updated_at=NOW()';
                if ($roomSet) $pdo->prepare('UPDATE rooms SET ' . implode(', ', $roomSet) . ' WHERE id=:id')->execute([':id' => $roomId]);
            }
        }
    }
}

if (!function_exists('arrivals_mark_no_show')) {
    function arrivals_mark_no_show(PDO $pdo, int $orderId, string $policyAction, float $policyAdjustmentAmount, float $policyChargeAmount, string $reason, bool $releaseRooms, string $selectedDate): void
    {
        if ($orderId <= 0) throw new RuntimeException('Invalid booking selected.');
        $validPolicyActions = ['keep_balance', 'waive_all', 'waive_and_charge_policy'];
        if (!in_array($policyAction, $validPolicyActions, true)) {
            throw new RuntimeException('Invalid no-show accounting option selected.');
        }

        $stmt = $pdo->prepare("SELECT o.*, g.firstname, g.lastname FROM orders o LEFT JOIN guests g ON g.id=o.guest_id WHERE o.id=:id LIMIT 1");
        $stmt->execute([':id'=>$orderId]);
        $order = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$order) throw new RuntimeException('Booking not found.');

        $stmt = $pdo->prepare("SELECT COUNT(*) FROM order_rooming WHERE order_id=:id AND COALESCE(checked_in_status,0)=1");
        $stmt->execute([':id'=>$orderId]);
        if ((int)$stmt->fetchColumn() > 0) {
            throw new RuntimeException('This booking already has checked-in room slots and cannot be marked as no-show from Arrivals.');
        }

        arrivals_try_add_column($pdo, 'orders', 'booking_status', '`booking_status` VARCHAR(40) NULL AFTER `status`');
        arrivals_try_add_column($pdo, 'orders', 'no_show_at', '`no_show_at` DATETIME NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_reason', '`no_show_reason` VARCHAR(255) NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_by', '`no_show_by` INT UNSIGNED NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_fee_posted', '`no_show_fee_posted` TINYINT(1) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_policy_action', '`no_show_policy_action` VARCHAR(40) NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_original_balance', '`no_show_original_balance` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_adjustment_amount', '`no_show_adjustment_amount` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_policy_charge', '`no_show_policy_charge` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_final_balance', '`no_show_final_balance` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_inventory_released', '`no_show_inventory_released` TINYINT(1) NOT NULL DEFAULT 0');

        $policyResult = arrivals_apply_no_show_policy_to_folio($pdo, $order, $policyAction, $policyAdjustmentAmount, $policyChargeAmount, $reason, $selectedDate);

        $sets = [];
        $params = [':id'=>$orderId];
        arrivals_safe_set_booking_status($pdo, 'no_show', $sets, $params, ':booking_status');
        if (arrivals_column_exists($pdo, 'orders', 'no_show_at')) $sets[] = 'no_show_at = NOW()';
        if (arrivals_column_exists($pdo, 'orders', 'no_show_reason')) { $sets[] = 'no_show_reason = :reason'; $params[':reason'] = $reason !== '' ? $reason : 'Guest did not arrive.'; }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_by')) { $sets[] = 'no_show_by = :uid'; $params[':uid'] = arrivals_current_user_id(); }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_fee_posted')) { $sets[] = 'no_show_fee_posted = :fee_posted'; $params[':fee_posted'] = ($policyResult['policy_charge'] > 0 ? 1 : 0); }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_policy_action')) { $sets[] = 'no_show_policy_action = :policy_action'; $params[':policy_action'] = $policyAction; }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_original_balance')) { $sets[] = 'no_show_original_balance = :original_balance'; $params[':original_balance'] = $policyResult['original_balance']; }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_adjustment_amount')) { $sets[] = 'no_show_adjustment_amount = :adjustment_amount'; $params[':adjustment_amount'] = $policyResult['adjustment_amount']; }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_policy_charge')) { $sets[] = 'no_show_policy_charge = :policy_charge'; $params[':policy_charge'] = $policyResult['policy_charge']; }
        if (arrivals_column_exists($pdo, 'orders', 'no_show_final_balance')) { $sets[] = 'no_show_final_balance = :final_balance'; $params[':final_balance'] = $policyResult['final_balance']; }
        if (arrivals_column_exists($pdo, 'orders', 'updated_at')) $sets[] = 'updated_at = NOW()';
        if (arrivals_column_exists($pdo, 'orders', 'updated_on')) $sets[] = 'updated_on = NOW()';
        if ($sets) $pdo->prepare('UPDATE orders SET ' . implode(', ', $sets) . ' WHERE id=:id')->execute($params);

        if ($releaseRooms) {
            arrivals_release_no_show_rooms($pdo, $orderId, $reason);
            if (arrivals_column_exists($pdo, 'orders', 'no_show_inventory_released')) {
                $pdo->prepare('UPDATE orders SET no_show_inventory_released = 1 WHERE id=:id')->execute([':id'=>$orderId]);
            }
        }
    }
}

$today = date('Y-m-d');
$selectedDate = trim((string)($_GET['arrival_date'] ?? $today));
$search = trim((string)($_GET['q'] ?? ''));
$propertyId = (int)($_GET['property_id'] ?? 0);

$errors = [];
$arrivals = [];

$properties = [];
try {
    $stmt = $pdo->query("
        SELECT id, name, code
        FROM properties
        WHERE is_active = 1
        ORDER BY name ASC
    ");
    $properties = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
    $properties = [];
}

$flashes = arrivals_get_flash();

try {
    if (arrivals_table_exists($pdo, 'orders')) {
        arrivals_try_add_column($pdo, 'orders', 'booking_status', '`booking_status` VARCHAR(40) NULL AFTER `status`');
        arrivals_try_add_column($pdo, 'orders', 'no_show_at', '`no_show_at` DATETIME NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_reason', '`no_show_reason` VARCHAR(255) NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_policy_action', '`no_show_policy_action` VARCHAR(40) NULL');
        arrivals_try_add_column($pdo, 'orders', 'no_show_original_balance', '`no_show_original_balance` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_adjustment_amount', '`no_show_adjustment_amount` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_policy_charge', '`no_show_policy_charge` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_final_balance', '`no_show_final_balance` DECIMAL(12,2) NOT NULL DEFAULT 0');
        arrivals_try_add_column($pdo, 'orders', 'no_show_inventory_released', '`no_show_inventory_released` TINYINT(1) NOT NULL DEFAULT 0');
    }
} catch (Throwable $e) {}

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

        if ($action === 'mark_no_show') {
            $postOrderId = (int)($_POST['order_id'] ?? 0);
            $policyAction = trim((string)($_POST['policy_action'] ?? 'keep_balance'));
            $policyAdjustmentAmount = (float)($_POST['policy_adjustment_amount'] ?? 0);
            $policyChargeAmount = (float)($_POST['policy_charge_amount'] ?? 0);
            $reason = trim((string)($_POST['no_show_reason'] ?? ''));
            $releaseRooms = !empty($_POST['release_rooms']);
            $redirectDate = trim((string)($_POST['arrival_date'] ?? $selectedDate));
            if (strtotime($redirectDate) === false) $redirectDate = $selectedDate;
            $redirectDate = date('Y-m-d', strtotime($redirectDate));

            $pdo->beginTransaction();
            arrivals_mark_no_show($pdo, $postOrderId, $policyAction, $policyAdjustmentAmount, $policyChargeAmount, $reason, $releaseRooms, $redirectDate);
            $pdo->commit();

            arrivals_flash('success', 'Booking marked as No Show and policy accounting applied.');
            $qs = ['arrival_date' => $redirectDate];
            if ($propertyId > 0) $qs['property_id'] = $propertyId;
            if ($search !== '') $qs['q'] = $search;
            header('Location: arrivals_today.php?' . http_build_query($qs));
            exit;
        }
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        arrivals_flash('danger', $e->getMessage());
        $qs = ['arrival_date' => $selectedDate];
        if ($propertyId > 0) $qs['property_id'] = $propertyId;
        if ($search !== '') $qs['q'] = $search;
        header('Location: arrivals_today.php?' . http_build_query($qs));
        exit;
    }
}

/*
  Main arrivals query.
  We compute:
  - total room slots
  - checked-in room slots
  - booking folio totals
*/
$sql = "
    SELECT
        o.*,
        p.name AS property_name,
        p.code AS property_code,
        rmix.room_mix,
        COALESCE(rmix.triple_slots_total, 0) AS triple_slots_total,
        COALESCE(rmix.family_slots_total, 0) AS family_slots_total,
        g.firstname,
        g.lastname,
        CONCAT(COALESCE(a.firstname,''), ' ', COALESCE(a.lastname,'')) AS agent_name,

        (
            SELECT COUNT(*)
            FROM order_rooming rmg
            WHERE rmg.order_id = o.id
        ) AS room_slots_total,

        (
            SELECT COUNT(*)
            FROM order_rooming rmg
            WHERE rmg.order_id = o.id
              AND COALESCE(rmg.checked_in_status,0) = 1
        ) AS room_slots_checked_in,

        (
            SELECT COUNT(*)
            FROM order_rooming rmg
            WHERE rmg.order_id = o.id
              AND COALESCE(rmg.checked_out_status,0) = 1
        ) AS room_slots_checked_out,

        (
            SELECT COALESCE(SUM(f.total_charges),0)
            FROM folios f
            WHERE f.order_id = o.id
        ) AS folio_total_charges,

        (
            SELECT COALESCE(SUM(f.total_payments),0)
            FROM folios f
            WHERE f.order_id = o.id
        ) AS folio_total_payments,

        (
            SELECT COALESCE(SUM(f.balance),0)
            FROM folios f
            WHERE f.order_id = o.id
        ) AS folio_total_balance

    FROM orders o
    LEFT JOIN properties p ON p.id = o.property_id
    LEFT JOIN guests g ON g.id = o.guest_id
    LEFT JOIN agents a ON a.id = o.agent_id
    LEFT JOIN (
        SELECT order_id,
               GROUP_CONCAT(room_summary ORDER BY sort_title SEPARATOR ', ') AS room_mix,
               SUM(triple_slots) AS triple_slots_total,
               SUM(family_slots) AS family_slots_total
        FROM (
            SELECT
                rmg.order_id,
                rt.title AS sort_title,
                SUM(CASE
                    WHEN (COALESCE(rmg.adults,0) + COALESCE(rmg.children,0)) = 3
                         AND LOWER(COALESCE(rt.title,'')) NOT LIKE '%family%'
                    THEN 1 ELSE 0 END
                ) AS triple_slots,
                SUM(CASE
                    WHEN LOWER(COALESCE(rt.title,'')) LIKE '%family%'
                    THEN 1 ELSE 0 END
                ) AS family_slots,
                CONCAT(
                    rt.title,
                    ' x ',
                    COUNT(*),
                    CASE
                        WHEN SUM(CASE
                            WHEN (COALESCE(rmg.adults,0) + COALESCE(rmg.children,0)) = 3
                                 AND LOWER(COALESCE(rt.title,'')) NOT LIKE '%family%'
                            THEN 1 ELSE 0 END
                        ) > 0
                        THEN CONCAT(
                            ' (',
                            SUM(CASE
                                WHEN (COALESCE(rmg.adults,0) + COALESCE(rmg.children,0)) = 3
                                     AND LOWER(COALESCE(rt.title,'')) NOT LIKE '%family%'
                                THEN 1 ELSE 0 END
                            ),
                            ' Triple / Extra Bed)'
                        )
                        ELSE ''
                    END,
                    CASE
                        WHEN SUM(CASE
                            WHEN LOWER(COALESCE(rt.title,'')) LIKE '%family%'
                            THEN 1 ELSE 0 END
                        ) > 0
                        THEN CONCAT(
                            ' (',
                            SUM(CASE
                                WHEN LOWER(COALESCE(rt.title,'')) LIKE '%family%'
                                THEN 1 ELSE 0 END
                            ),
                            ' Family)'
                        )
                        ELSE ''
                    END
                ) AS room_summary
            FROM order_rooming rmg
            INNER JOIN room_types rt ON rt.id = rmg.room_type_id
            GROUP BY rmg.order_id, rmg.room_type_id, rt.title
        ) mix
        GROUP BY order_id
    ) rmix ON rmix.order_id = o.id
    WHERE DATE(o.check_in) = :arrival_date
      AND CAST(COALESCE(o.status,1) AS CHAR) NOT IN ('0','cancelled','canceled')
      AND LOWER(COALESCE(o.booking_status,'')) NOT IN ('no_show','noshow','cancelled','canceled')
      AND o.no_show_at IS NULL
";

$params = [
    ':arrival_date' => $selectedDate,
];

if ($propertyId > 0) {
    $sql .= " AND o.property_id = :property_id ";
    $params[':property_id'] = $propertyId;
}

if ($search !== '') {
    $sql .= "
        AND (
            o.order_no LIKE :search
            OR CAST(o.id AS CHAR) LIKE :search
            OR g.firstname LIKE :search
            OR g.lastname LIKE :search
            OR CONCAT(COALESCE(a.firstname,''), ' ', COALESCE(a.lastname,'')) LIKE :search
        )
    ";
    $params[':search'] = '%' . $search . '%';
}

$sql .= " ORDER BY p.name ASC, o.check_in ASC, o.id DESC ";

try {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $arrivals = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
    $errors[] = $e->getMessage();
}

$totalArrivals = count($arrivals);
$totalPending = 0;
$totalCheckedIn = 0;
$totalPartial = 0;
$totalNoShow = 0;

foreach ($arrivals as $row) {
    $slotsTotal = (int)($row['room_slots_total'] ?? 0);
    $slotsChecked = (int)($row['room_slots_checked_in'] ?? 0);

    $orderStatus = strtolower(trim((string)($row['status'] ?? '')));
    if ($orderStatus === 'no_show') {
        $totalNoShow++;
    } elseif ($slotsTotal > 0 && $slotsChecked >= $slotsTotal) {
        $totalCheckedIn++;
    } elseif ($slotsChecked > 0) {
        $totalPartial++;
    } else {
        $totalPending++;
    }
}

require_once __DIR__ . '/../../includes/header.php';
?>
<style>
.arrivals-page-compact .hero-band{
    padding:14px 18px!important;
    border-radius:18px!important;
    margin-bottom:12px!important;
}
.arrivals-page-compact .hero-title{
    font-size:1.25rem!important;
    line-height:1.1!important;
    margin-top:.25rem!important;
}
.arrivals-page-compact .hero-subtitle{
    font-size:.82rem!important;
    margin-top:.25rem!important;
    line-height:1.25!important;
}
.arrivals-page-compact .page-eyebrow{
    font-size:.72rem!important;
}
.arrivals-page-compact .metric-row{
    margin-bottom:12px!important;
}
.arrivals-page-compact .metric-card{
    padding:10px 12px!important;
    border-radius:16px!important;
    min-height:auto!important;
}
.arrivals-page-compact .metric-icon{
    width:34px!important;
    height:34px!important;
    border-radius:11px!important;
    font-size:.9rem!important;
}
.arrivals-page-compact .metric-label{
    font-size:.72rem!important;
    margin-bottom:0!important;
}
.arrivals-page-compact .metric-value{
    font-size:1.08rem!important;
    line-height:1.1!important;
}
.arrivals-page-compact .filter-card{
    margin-bottom:12px!important;
}
.arrivals-page-compact .filter-card .card-header{
    padding:.55rem .9rem!important;
}
.arrivals-page-compact .filter-card .card-header h5{
    font-size:.9rem!important;
}
.arrivals-page-compact .filter-card .card-body{
    padding:.75rem .9rem!important;
}
.arrivals-page-compact .filter-card .form-label{
    font-size:.74rem!important;
    margin-bottom:.18rem!important;
    font-weight:700!important;
}
.arrivals-page-compact .filter-card .form-control,
.arrivals-page-compact .filter-card .form-select{
    min-height:34px!important;
    padding:.34rem .55rem!important;
    font-size:.84rem!important;
}
.arrivals-page-compact .filter-card .btn{
    min-height:34px!important;
    padding:.34rem .7rem!important;
}
.arrivals-page-compact .list-card .card-header{
    padding:.65rem .9rem!important;
}
.arrivals-page-compact .list-card .card-header h5{
    font-size:.95rem!important;
}
.arrivals-page-compact .list-card .card-header small{
    font-size:.72rem!important;
}
.arrivals-table-wrap{
    max-height:calc(100vh - 255px);
    overflow:auto;
    border-radius:0 0 16px 16px;
}
.arrivals-table-wrap table thead th{
    position:sticky;
    top:0;
    z-index:8;
    background:#f8fafc!important;
    box-shadow:0 1px 0 rgba(15,23,42,.08);
}
.arrivals-table-wrap .table td,
.arrivals-table-wrap .table th{
    white-space:nowrap;
}
.arrivals-table-wrap .table td:nth-child(6){
    white-space:normal;
    min-width:260px;
}
.arrivals-table-wrap .table td:nth-child(9){
    min-width:330px;
}
.arrival-room-badges{
    display:flex;
    flex-wrap:wrap;
    gap:.35rem;
    margin-top:.45rem;
}
.arrival-room-badge{
    display:inline-flex;
    align-items:center;
    gap:.25rem;
    border-radius:999px;
    padding:.2rem .5rem;
    font-size:.68rem;
    font-weight:800;
}
.arrival-room-badge.triple{
    background:#fff3cd;
    color:#8a5a00;
    border:1px solid #ffe69c;
}
.arrival-room-badge.family{
    background:#e7f1ff;
    color:#084298;
    border:1px solid #b6d4fe;
}
.frontdesk-action-group .btn{
    padding:.25rem .5rem!important;
    font-size:.76rem!important;
}
@media (max-width: 991.98px){
    .arrivals-table-wrap{
        max-height:none;
    }
    .arrivals-table-wrap table thead th{
        position:static;
    }
}
</style>
<div class="arrivals-page-compact">
<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-calendar-check"></i> Front Desk</div>
            <div class="hero-title mt-2">Arrivals Today</div>
            <div class="hero-subtitle mt-2">
                Arrivals, registration, folios and check-in actions in one compact operational view.
            </div>
        </div>
        <div class="col-lg-4 text-lg-end">
            <a href="/rooms/modules/reservations/reservation_list.php" class="btn btn-outline-light">
                <i class="bi bi-arrow-left me-2"></i>Reservations
            </a>
        </div>
    </div>
</div>

<?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; ?>

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

<div class="row g-2 metric-row">
    <div class="col-sm-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-primary-subtle text-primary">
                <i class="bi bi-people"></i>
            </div>
            <div>
                <div class="metric-label">Arrivals</div>
                <div class="metric-value"><?php echo number_format($totalArrivals); ?></div>
            </div>
        </div>
    </div>

    <div class="col-sm-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-secondary-subtle text-secondary">
                <i class="bi bi-hourglass-split"></i>
            </div>
            <div>
                <div class="metric-label">Pending</div>
                <div class="metric-value"><?php echo number_format($totalPending); ?></div>
            </div>
        </div>
    </div>

    <div class="col-sm-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-warning-subtle text-warning">
                <i class="bi bi-person-check"></i>
            </div>
            <div>
                <div class="metric-label">Partial</div>
                <div class="metric-value"><?php echo number_format($totalPartial); ?></div>
            </div>
        </div>
    </div>

    <div class="col-sm-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-success-subtle text-success">
                <i class="bi bi-check2-circle"></i>
            </div>
            <div>
                <div class="metric-label">Checked In</div>
                <div class="metric-value"><?php echo number_format($totalCheckedIn); ?></div>
            </div>
        </div>
    </div>

    <div class="col-sm-6 col-xl-3">
        <div class="metric-card">
            <div class="metric-icon bg-danger-subtle text-danger">
                <i class="bi bi-person-x"></i>
            </div>
            <div>
                <div class="metric-label">No Shows</div>
                <div class="metric-value"><?php echo number_format($totalNoShow); ?></div>
            </div>
        </div>
    </div>
</div>

<div class="card panel-card filter-card">
    <div class="card-header">
        <h5 class="mb-0">Search & Filters</h5>
    </div>
    <div class="card-body">
        <form method="get" class="row g-3 align-items-end">
            <div class="col-md-3">
                <label class="form-label">Arrival Date</label>
                <input type="date" name="arrival_date" class="form-control" value="<?php echo h($selectedDate); ?>">
            </div>

            <div class="col-md-3">
                <label class="form-label">Property</label>
                <select name="property_id" class="form-select">
                    <option value="0">All properties</option>
                    <?php foreach ($properties as $property): ?>
                        <option value="<?php echo (int)$property['id']; ?>" <?php echo $propertyId === (int)$property['id'] ? 'selected' : ''; ?>>
                            <?php echo h($property['name']); ?><?php echo !empty($property['code']) ? ' - ' . h($property['code']) : ''; ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>

            <div class="col-md-5">
                <label class="form-label">Search</label>
                <input type="text" name="q" class="form-control" value="<?php echo h($search); ?>" placeholder="Booking no, guest, agent...">
            </div>

            <div class="col-md-1 d-grid">
                <button class="btn btn-primary">Go</button>
            </div>
        </form>
    </div>
</div>

<div class="card panel-card list-card">
    <div class="card-header d-flex justify-content-between align-items-center">
        <div>
            <h5 class="mb-0">Arrival List</h5>
            <small>Bookings arriving on <?php echo h($selectedDate); ?></small>
        </div>
    </div>

    <div class="card-body p-0">
        <div class="table-responsive arrivals-table-wrap">
            <table class="table table-modern align-middle mb-0">
                <thead>
                    <tr>
                        <th>Booking</th>
                        <th>Property</th>
                        <th>Guest</th>
                        <th>Agent</th>
                        <th>Stay</th>
                        <th>Room Mix / Pax</th>
                        <th>Check-In Status</th>
                        <th class="text-end">Folio Balance</th>
                        <th class="text-end">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (!$arrivals): ?>
                        <tr>
                            <td colspan="9" class="text-center text-muted py-5">
                                No arrivals found for the selected date.
                            </td>
                        </tr>
                    <?php else: ?>
                        <?php foreach ($arrivals as $row): ?>
                            <?php
                            $guestName = trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? ''));
                            if ($guestName === '') {
                                $guestName = 'Guest';
                            }

                            $agentName = trim((string)($row['agent_name'] ?? ''));
                            if ($agentName === '') {
                                $agentName = 'Direct';
                            }

                            $propertyLabel = trim((string)($row['property_name'] ?? ''));
                            if (!empty($row['property_code'])) {
                                $propertyLabel .= ($propertyLabel !== '' ? ' (' . $row['property_code'] . ')' : $row['property_code']);
                            }

                            $slotsTotal = (int)($row['room_slots_total'] ?? 0);
                            $slotsChecked = (int)($row['room_slots_checked_in'] ?? 0);
                            $slotsCheckedOut = (int)($row['room_slots_checked_out'] ?? 0);

                            $fullyCheckedIn = ($slotsTotal > 0 && $slotsChecked >= $slotsTotal);
                            $partlyCheckedIn = ($slotsChecked > 0 && !$fullyCheckedIn);
                            $hasCheckoutStarted = ($slotsCheckedOut > 0);
                            $fullyCheckedOut = ($slotsTotal > 0 && $slotsCheckedOut >= $slotsTotal);

                            /*
                               Arrival action rule:
                               - If the booking has started checkout or is fully checked out, never show Check Out here.
                               - If fully checked in, hide Check In and leave registration/folio actions visible.
                               - If partially checked in, show Continue Check-In for remaining room slots.
                               - If pending, show Check In.
                            */
                            $orderStatus = strtolower(trim((string)($row['status'] ?? '')));
                            $bookingStatus = strtolower(trim((string)($row['booking_status'] ?? '')));
                            $isNoShow = in_array($orderStatus, ['no_show','noshow'], true)
                                || in_array($bookingStatus, ['no_show','noshow'], true)
                                || !empty($row['no_show_at']);
                            $isCancelled = in_array($orderStatus, ['0','cancelled', 'canceled'], true)
                                || in_array($bookingStatus, ['cancelled','canceled'], true);

                            $showCheckIn = (!$fullyCheckedIn && !$fullyCheckedOut && !$isNoShow && !$isCancelled);
                            $checkInLabel = $partlyCheckedIn ? 'Continue Check-In' : 'Check In';

                            if ($isNoShow) {
                                $arrivalStatus = 'no_show';
                            } elseif ($isCancelled) {
                                $arrivalStatus = 'cancelled';
                            } elseif ($slotsTotal > 0 && $slotsChecked >= $slotsTotal) {
                                $arrivalStatus = 'checked_in';
                            } elseif ($slotsChecked > 0) {
                                $arrivalStatus = 'partial';
                            } else {
                                $arrivalStatus = 'pending';
                            }

                            $arrivalDateOnly = date('Y-m-d', strtotime((string)$row['check_in']));
                            $canMarkNoShow = (!$isNoShow && !$isCancelled && !$fullyCheckedIn && !$partlyCheckedIn && !$fullyCheckedOut && $arrivalDateOnly <= date('Y-m-d'));
                            $balance = (float)($row['folio_total_balance'] ?? 0);
                            $tripleSlots = (int)($row['triple_slots_total'] ?? 0);
                            $familySlots = (int)($row['family_slots_total'] ?? 0);
                            ?>
                            <tr>
                                <td>
                                    <div class="data-stack">
                                        <strong><?php echo h($row['order_no'] ?: ('#' . $row['id'])); ?></strong>
                                        <small>Booking ID <?php echo (int)$row['id']; ?></small>
                                    </div>
                                </td>

                                <td><?php echo h($propertyLabel !== '' ? $propertyLabel : 'Not set'); ?></td>
                                <td><?php echo h($guestName); ?></td>
                                <td><?php echo h($agentName); ?></td>

                                <td>
                                    <div class="data-stack">
                                        <strong><?php echo h($row['check_in']); ?></strong>
                                        <small>to <?php echo h($row['check_out']); ?></small>
                                    </div>
                                </td>

                                <td>
                                    <?php if (!empty($row['room_mix'])): ?>
                                        <div class="fw-semibold"><?php echo h($row['room_mix']); ?></div>
                                    <?php else: ?>
                                        <div class="fw-semibold text-muted">Room mix not set</div>
                                    <?php endif; ?>

                                    <?php if ($tripleSlots > 0 || $familySlots > 0): ?>
                                        <div class="arrival-room-badges">
                                            <?php if ($tripleSlots > 0): ?>
                                                <span class="arrival-room-badge triple">
                                                    <i class="bi bi-person-plus"></i>
                                                    <?php echo $tripleSlots; ?> Triple / Extra Bed
                                                </span>
                                            <?php endif; ?>
                                            <?php if ($familySlots > 0): ?>
                                                <span class="arrival-room-badge family">
                                                    <i class="bi bi-people"></i>
                                                    <?php echo $familySlots; ?> Family Room
                                                </span>
                                            <?php endif; ?>
                                        </div>
                                    <?php endif; ?>

                                    <div class="small text-muted mt-1">
                                        <?php echo (int)($row['totalrooms'] ?? 1); ?> room(s) •
                                        <?php echo (int)($row['adults'] ?? 0); ?>A /
                                        <?php echo (int)($row['kids'] ?? 0); ?>C
                                    </div>
                                    <div class="small text-muted mt-1">
                                        Room slots checked in: <?php echo $slotsChecked; ?>/<?php echo $slotsTotal; ?>
                                        <?php if ($slotsCheckedOut > 0): ?>
                                            • Checked out: <?php echo $slotsCheckedOut; ?>/<?php echo $slotsTotal; ?>
                                        <?php endif; ?>
                                    </div>
                                </td>

                                <td><?php echo arrival_status_badge($arrivalStatus); ?></td>

                                <td class="text-end">
                                    <span class="badge text-bg-<?php echo $balance > 0.00001 ? 'warning' : 'success'; ?> px-3 py-2">
                                        <?php echo money_fmt($balance); ?>
                                    </span>
                                </td>

                                <td class="text-end">
                                    <div class="d-inline-flex gap-2 flex-wrap justify-content-end frontdesk-action-group">
                                        <?php if ($showCheckIn): ?>
                                            <a href="/rooms/modules/payments/checkin.php?order_id=<?php echo (int)$row['id']; ?>"
                                               class="btn btn-sm btn-success">
                                                <i class="bi bi-door-open me-1"></i><?php echo h($checkInLabel); ?>
                                            </a>
                                        <?php endif; ?>

                                        <a href="/rooms/modules/reservations/guest_registration_pdf.php?order_id=<?php echo (int)$row['id']; ?>"
                                           class="btn btn-sm btn-outline-dark">
                                            <i class="bi bi-person-vcard me-1"></i>Guest Reg.
                                        </a>

                                        <a href="/rooms/modules/reservations/guest_registration_pdf.php?order_id=<?php echo (int)$row['id']; ?>"
                                           target="_blank"
                                           class="btn btn-sm btn-outline-danger">
                                            <i class="bi bi-file-earmark-pdf me-1"></i>PDF Preview
                                        </a>

                                        <a href="/rooms/modules/payments/payments.php?order_id=<?php echo (int)$row['id']; ?>"
                                           class="btn btn-sm btn-outline-primary">
                                            <i class="bi bi-cash-stack me-1"></i>Payments
                                        </a>

                                        <a href="/rooms/modules/payments/folio.php?order_id=<?php echo urlencode((string)($row['id'] ?: $row['id'])); ?>"
                                           class="btn btn-sm btn-outline-secondary">
                                            <i class="bi bi-receipt me-1"></i>Folios
                                        </a>

                                        <?php if ($canMarkNoShow): ?>
                                            <button type="button"
                                                    class="btn btn-sm btn-outline-danger"
                                                    data-bs-toggle="modal"
                                                    data-bs-target="#noShowModal<?php echo (int)$row['id']; ?>">
                                                <i class="bi bi-person-x me-1"></i>No Show
                                            </button>
                                        <?php endif; ?>

                                        <a href="/rooms/modules/reservations/reservation_view.php?order_id=<?php echo (int)$row['id']; ?>"
                                           class="btn btn-sm btn-light">
                                            <i class="bi bi-eye me-1"></i>View
                                        </a>
                                    </div>
                                </td>
                            </tr>

                            <?php if ($canMarkNoShow): ?>
                                <div class="modal fade" id="noShowModal<?php echo (int)$row['id']; ?>" tabindex="-1" aria-hidden="true">
                                    <div class="modal-dialog modal-dialog-centered">
                                        <div class="modal-content border-0 shadow-lg">
                                            <div class="modal-header bg-danger text-white">
                                                <h5 class="modal-title">
                                                    <i class="bi bi-person-x me-2"></i>Mark Arrival as No Show
                                                </h5>
                                                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
                                            </div>
                                            <form method="post">
                                                <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                                                <input type="hidden" name="action" value="mark_no_show">
                                                <input type="hidden" name="order_id" value="<?php echo (int)$row['id']; ?>">
                                                <input type="hidden" name="arrival_date" value="<?php echo h($selectedDate); ?>">
                                                <div class="modal-body">
                                                    <div class="alert alert-warning">
                                                        <strong><?php echo h($row['order_no'] ?: ('#' . $row['id'])); ?></strong><br>
                                                        <?php echo h($guestName); ?> did not arrive. This will mark the booking as <strong>No Show</strong> and keep it visible for audit/reporting.
                                                    </div>

                                                    <div class="mb-3">
                                                        <label class="form-label">Current Folio Balance</label>
                                                        <input type="text" class="form-control no-show-current-balance" value="<?php echo money_fmt($balance); ?>" readonly data-balance="<?php echo h(number_format($balance, 2, '.', '')); ?>">
                                                        <div class="form-text">This is the current outstanding folio balance before no-show processing.</div>
                                                    </div>

                                                    <div class="mb-3">
                                                        <label class="form-label">No-Show Policy Action</label>
                                                        <div class="vstack gap-2">
                                                            <label class="border rounded-3 p-2">
                                                                <input type="radio" name="policy_action" value="keep_balance" class="form-check-input me-2 no-show-policy-action" checked>
                                                                <strong>Charge Existing Folio As Is</strong>
                                                                <div class="small text-muted">No new charge is posted. The final no-show balance remains the current folio balance.</div>
                                                            </label>
                                                            <label class="border rounded-3 p-2">
                                                                <input type="radio" name="policy_action" value="waive_all" class="form-check-input me-2 no-show-policy-action">
                                                                <strong>Waive Entire Folio Balance</strong>
                                                                <div class="small text-muted">Posts a no-show adjustment credit equal to the current balance. Final balance becomes 0.00.</div>
                                                            </label>
                                                            <label class="border rounded-3 p-2">
                                                                <input type="radio" name="policy_action" value="waive_and_charge_policy" class="form-check-input me-2 no-show-policy-action">
                                                                <strong>Waive Then Charge No-Show Policy Amount</strong>
                                                                <div class="small text-muted">Posts an adjustment first, then posts the policy charge amount below.</div>
                                                            </label>
                                                        </div>
                                                    </div>

                                                    <div class="row g-2 mb-3">
                                                        <div class="col-md-6">
                                                            <label class="form-label">No-Show Adjustment / Waiver</label>
                                                            <input type="number" step="0.01" min="0" name="policy_adjustment_amount" class="form-control no-show-adjustment" value="0.00" readonly>
                                                            <div class="form-text">Credit adjustment posted against existing folio balance.</div>
                                                        </div>
                                                        <div class="col-md-6">
                                                            <label class="form-label">No Show Policy Charge</label>
                                                            <input type="number" step="0.01" min="0" name="policy_charge_amount" class="form-control no-show-charge" value="<?php echo h(number_format($balance, 2, '.', '')); ?>" readonly>
                                                            <div class="form-text no-show-charge-help">For Charge Existing Folio As Is, this shows the final balance but no extra charge is posted.</div>
                                                        </div>
                                                    </div>

                                                    <div class="mb-3">
                                                        <label class="form-label">Reason / Notes</label>
                                                        <textarea name="no_show_reason" rows="3" class="form-control" placeholder="Guest did not arrive / could not be contacted / policy applied..."></textarea>
                                                    </div>

                                                    <div class="form-check">
                                                        <input class="form-check-input" type="checkbox" name="release_rooms" value="1" id="releaseRooms<?php echo (int)$row['id']; ?>" checked>
                                                        <label class="form-check-label" for="releaseRooms<?php echo (int)$row['id']; ?>">
                                                            Release assigned physical room(s) back to available/clean
                                                        </label>
                                                    </div>
                                                </div>
                                                <div class="modal-footer">
                                                    <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                                                    <button type="submit" class="btn btn-danger" onclick="return confirm('Mark this booking as No Show?');">
                                                        <i class="bi bi-person-x me-1"></i>Confirm No Show
                                                    </button>
                                                </div>
                                            </form>
                                        </div>
                                    </div>
                                </div>
                            <?php endif; ?>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </tbody>
            </table>
        </div>
    </div>
</div>

</div>
<script>
document.addEventListener('change', function (event) {
    if (!event.target.classList.contains('no-show-policy-action')) return;
    const modal = event.target.closest('.modal');
    if (!modal) return;
    const balanceInput = modal.querySelector('.no-show-current-balance');
    const adjustmentInput = modal.querySelector('.no-show-adjustment');
    const chargeInput = modal.querySelector('.no-show-charge');
    const help = modal.querySelector('.no-show-charge-help');
    const balance = parseFloat(balanceInput ? balanceInput.dataset.balance : '0') || 0;
    const fmt = balance.toFixed(2);
    const action = event.target.value;

    if (action === 'keep_balance') {
        adjustmentInput.value = '0.00';
        adjustmentInput.readOnly = true;
        chargeInput.value = fmt;
        chargeInput.readOnly = true;
        chargeInput.classList.add('bg-light');
        help.textContent = 'For Charge Existing Folio As Is, this shows the final balance but no extra charge is posted.';
    } else if (action === 'waive_all') {
        adjustmentInput.value = fmt;
        adjustmentInput.readOnly = true;
        chargeInput.value = '0.00';
        chargeInput.readOnly = true;
        chargeInput.classList.add('bg-light');
        help.textContent = 'Waive Entire Folio Balance posts no extra no-show charge. Final balance becomes 0.00.';
    } else {
        adjustmentInput.value = fmt;
        adjustmentInput.readOnly = false;
        chargeInput.value = '0.00';
        chargeInput.readOnly = false;
        chargeInput.classList.remove('bg-light');
        help.textContent = 'Enter the actual no-show policy charge to post after the adjustment.';
    }
});

document.querySelectorAll('.modal').forEach(function (modal) {
    const checked = modal.querySelector('.no-show-policy-action:checked');
    if (checked) checked.dispatchEvent(new Event('change', {bubbles: true}));
});
</script>
<?php require_once __DIR__ . '/../../includes/footer.php'; ?>