<?php
declare(strict_types=1);

namespace App\Modules\Reservations\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Modules\Reservations\Models\Reservation;
use App\Modules\Facilities\Models\Facility;
use App\Modules\Rules\Services\RuleEngine;

class ReservationService
{
    /**
     * Create a new reservation.
     *
     * Generates a reservation number, calculates duration and total,
     * checks for conflicts, and creates the record.
     */
    public static function create(array $data): array
    {
        // Check for conflicts first
        $conflicts = FacilityConflictDetector::checkConflicts(
            (int) $data['facility_id'],
            $data['reservation_date'],
            $data['start_time'],
            $data['end_time']
        );

        if (!empty($conflicts)) {
            return ['success' => false, 'conflicts' => $conflicts];
        }

        // Generate reservation number
        $data['reservation_number'] = self::generateNumber();

        // Calculate duration in hours
        $start = strtotime($data['reservation_date'] . ' ' . $data['start_time']);
        $end   = strtotime($data['reservation_date'] . ' ' . $data['end_time']);
        $durationHours = ($end - $start) / 3600;
        $data['duration_hours'] = round($durationHours, 2);

        // Determine time tier if not provided
        if (empty($data['time_tier'])) {
            $hour = (int) date('H', strtotime($data['start_time']));
            $pmStartHour = (int) (RuleEngine::getValue('SPORTS_PM_START_HOUR', 'hour') ?? 17);
            $data['time_tier'] = $hour < $pmStartHour ? 'AM' : 'PM';
        }

        // Calculate unit rate and total amount if facility is set
        if (!empty($data['facility_id']) && empty($data['unit_rate'])) {
            $facility = Facility::find((int) $data['facility_id']);
            if ($facility) {
                $isMember = in_array($data['booker_type'] ?? '', ['member', 'player']);
                $data['unit_rate'] = $facility->getRate($isMember, $data['time_tier']);
            }
        }

        if (empty($data['total_amount']) && !empty($data['unit_rate'])) {
            $data['total_amount'] = bcmul((string) $data['unit_rate'], (string) $data['duration_hours'], 2);
        }

        // Default status
        if (empty($data['status'])) {
            $data['status'] = 'pending';
        }

        $reservation = Reservation::create($data);

        EventBus::dispatch('reservation.created', [
            'reservation_id' => (int) $reservation->id,
            'facility_id'    => (int) $data['facility_id'],
            'date'           => $data['reservation_date'],
        ]);

        return ['success' => true, 'reservation' => $reservation];
    }

    /**
     * Confirm a reservation.
     */
    public static function confirm(int $reservationId): bool
    {
        $reservation = Reservation::find($reservationId);
        if (!$reservation) {
            return false;
        }

        $reservation->update([
            'status'       => 'confirmed',
            'confirmed_at' => date('Y-m-d H:i:s'),
        ]);

        EventBus::dispatch('reservation.confirmed', [
            'reservation_id' => $reservationId,
        ]);

        return true;
    }

    /**
     * Cancel a reservation with an optional reason.
     */
    public static function cancel(int $reservationId, ?string $reason = null): bool
    {
        $reservation = Reservation::find($reservationId);
        if (!$reservation) {
            return false;
        }

        $reservation->update([
            'status'        => 'cancelled',
            'cancelled_at'  => date('Y-m-d H:i:s'),
            'cancel_reason' => $reason,
        ]);

        EventBus::dispatch('reservation.cancelled', [
            'reservation_id' => $reservationId,
        ]);

        return true;
    }

    /**
     * Check in a reservation (mark as checked_in).
     */
    public static function checkIn(int $reservationId): bool
    {
        $reservation = Reservation::find($reservationId);
        if (!$reservation) {
            return false;
        }

        $reservation->update([
            'status' => 'checked_in',
        ]);

        return true;
    }

    /**
     * Generate a unique reservation number (RES-YYYYMMDD-XXXX).
     */
    public static function generateNumber(): string
    {
        return Reservation::generateNumber();
    }
}
