<?php

namespace App\Commands;

use App\Models\BookingModel;
use App\Models\Control\TenantRecordModel;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

/**
 * A booking made through the public booking widget
 * (WidgetBookingController) is held as 'pending_deposit' the moment it's
 * created — before the guest has actually paid — the exact same status
 * the staff wizard's "pay via link" path already uses. Unlike the staff
 * flow (where a real person is present and will notice/rebook if a link
 * goes unpaid), a widget booking has zero staff review at all, so a
 * visitor who abandons payment mid-checkout would otherwise hold a real
 * room forever. This batch job cancels any 'pending_deposit' booking
 * older than 60 minutes, freeing the room for other guests — cancelling
 * is enough on its own: BookingModel::hasOverlap()/RoomModel::
 * findAvailable() only count pending_deposit/confirmed/checked_in
 * bookings as blocking, so a cancelled one is immediately searchable
 * again with no separate "free the room" step needed.
 *
 * Same "loop every active tenant" shape as SendBirthdayOffers/
 * SendPreArrivalReminders. Meant to run periodically via cron/Task
 * Scheduler (no framework-internal scheduler exists in this app — see
 * those two commands' own doc comments for the same caveat):
 *   php spark bookings:expire-pending-deposits
 */
class ExpirePendingDepositBookings extends BaseCommand
{
    protected $group       = 'Bookings';
    protected $name        = 'bookings:expire-pending-deposits';
    protected $description = 'Cancels widget/online bookings still awaiting deposit payment after 60 minutes, freeing the room.';

    private const EXPIRY_MINUTES = 60;

    public function run(array $params)
    {
        $tenants = (new TenantRecordModel())->where('status', 'active')->findAll();

        foreach ($tenants as $tenant) {
            $this->expireForTenant($tenant);
        }
    }

    private function expireForTenant(object $tenant): void
    {
        service('tenantContext')->setTenant($tenant);

        $cutoff   = date('Y-m-d H:i:s', strtotime('-' . self::EXPIRY_MINUTES . ' minutes'));
        $bookings = new BookingModel();

        $stale = $bookings->where('status', 'pending_deposit')->where('created_at <', $cutoff)->findAll();

        if ($stale === []) {
            CLI::write("{$tenant->slug}: no stale pending-deposit bookings.", 'white');

            return;
        }

        foreach ($stale as $booking) {
            $bookings->update($booking->id, ['status' => 'cancelled']);
        }

        CLI::write("{$tenant->slug}: cancelled " . count($stale) . ' stale pending-deposit booking(s).', 'green');
    }
}
