<?php
declare(strict_types=1);

namespace App\Modules\PlayerApi\Services;

use App\Core\App;
use App\Core\EventBus;

final class PlayerBookingService
{
    private \App\Core\Database $db;

    public function __construct()
    {
        $this->db = App::getInstance()->db();
    }

    public function getBookableFacilities(): array
    {
        return $this->db->select(
            "SELECT id, name_ar, facility_type, location, hourly_rate_member, hourly_rate_nonmember
             FROM facilities WHERE is_active = 1 AND is_archived = 0
             AND facility_type IN ('pitch', 'court', 'hall', 'table', 'device')
             ORDER BY name_ar"
        );
    }

    public function getAvailability(int $facilityId, string $date): array
    {
        $facility = $this->db->selectOne(
            "SELECT * FROM facilities WHERE id = ? AND is_active = 1 AND is_archived = 0",
            [$facilityId]
        );

        if (!$facility) {
            return [];
        }

        $dayOfWeek = (int) date('w', strtotime($date));

        $timeSlots = $this->db->select(
            "SELECT start_time, end_time, access_type, member_price, guest_price
             FROM facility_time_slots
             WHERE facility_id = ? AND day_of_week = ? AND is_active = 1",
            [$facilityId, $dayOfWeek]
        );

        $existingBookings = $this->db->select(
            "SELECT start_time, end_time FROM reservations
             WHERE facility_id = ? AND reservation_date = ? AND status NOT IN ('cancelled', 'no_show')",
            [$facilityId, $date]
        );

        $available = [];
        foreach ($timeSlots as $slot) {
            $isBooked = false;
            foreach ($existingBookings as $booking) {
                if ($slot['start_time'] < $booking['end_time'] && $slot['end_time'] > $booking['start_time']) {
                    $isBooked = true;
                    break;
                }
            }
            $slot['is_available'] = !$isBooked;
            $available[] = $slot;
        }

        return $available;
    }

    public function createBooking(int $playerId, array $data): array
    {
        $player = App::getInstance()->currentPlayer();
        $isMember = !empty($player->member_id);

        $facility = $this->db->selectOne(
            "SELECT * FROM facilities WHERE id = ? AND is_active = 1 AND is_archived = 0",
            [$data['facility_id']]
        );

        if (!$facility) {
            return ['error' => 'الملعب غير متاح'];
        }

        $conflict = $this->db->selectOne(
            "SELECT id FROM reservations
             WHERE facility_id = ? AND reservation_date = ? AND status NOT IN ('cancelled', 'no_show')
             AND start_time < ? AND end_time > ?",
            [$data['facility_id'], $data['date'], $data['end_time'], $data['start_time']]
        );

        if ($conflict) {
            return ['error' => 'الوقت المطلوب محجوز بالفعل'];
        }

        $rate = $isMember
            ? (float) ($facility['hourly_rate_member'] ?? $facility['hourly_rate_nonmember'])
            : (float) $facility['hourly_rate_nonmember'];

        $hours = (strtotime($data['end_time']) - strtotime($data['start_time'])) / 3600;
        $totalAmount = $rate * $hours;

        $reservationNumber = 'RES-' . date('Ymd') . '-' . str_pad((string) random_int(1, 9999), 4, '0', STR_PAD_LEFT);

        $this->db->insert('reservations', [
            'reservation_number' => $reservationNumber,
            'facility_id' => $data['facility_id'],
            'booker_type' => 'player',
            'booker_id' => $playerId,
            'reservation_date' => $data['date'],
            'start_time' => $data['start_time'],
            'end_time' => $data['end_time'],
            'status' => 'confirmed',
            'unit_rate' => $rate,
            'total_amount' => $totalAmount,
            'notes' => $data['notes'] ?? null,
        ]);

        $bookingId = (int) $this->db->selectOne("SELECT LAST_INSERT_ID() as id")['id'];

        EventBus::dispatch('player.booking_confirmed', [
            'player_id' => $playerId,
            'booking_id' => $bookingId,
            'facility_name' => $facility['name_ar'],
            'date' => $data['date'],
        ]);

        return [
            'id' => $bookingId,
            'reservation_number' => $reservationNumber,
            'total_amount' => $totalAmount,
        ];
    }

    public function getPlayerBookings(int $playerId, int $page = 1, int $perPage = 25): array
    {
        $total = (int) ($this->db->selectOne(
            "SELECT COUNT(*) as cnt FROM reservations WHERE booker_type = 'player' AND booker_id = ?",
            [$playerId]
        )['cnt'] ?? 0);

        $lastPage = max(1, (int) ceil($total / $perPage));
        $page = min($page, $lastPage);
        $offset = ($page - 1) * $perPage;

        $items = $this->db->select(
            "SELECT r.*, f.name_ar as facility_name, f.facility_type
             FROM reservations r
             LEFT JOIN facilities f ON f.id = r.facility_id
             WHERE r.booker_type = 'player' AND r.booker_id = ?
             ORDER BY r.reservation_date DESC, r.start_time DESC
             LIMIT ? OFFSET ?",
            [$playerId, $perPage, $offset]
        );

        return [
            'data' => $items,
            'pagination' => ['total' => $total, 'per_page' => $perPage, 'current_page' => $page, 'last_page' => $lastPage],
        ];
    }

    public function cancelBooking(int $bookingId, int $playerId): bool
    {
        $booking = $this->db->selectOne(
            "SELECT id, status FROM reservations WHERE id = ? AND booker_type = 'player' AND booker_id = ?",
            [$bookingId, $playerId]
        );

        if (!$booking || $booking['status'] === 'cancelled') {
            return false;
        }

        $this->db->update('reservations', ['status' => 'cancelled'], 'id = ?', [$bookingId]);

        EventBus::dispatch('player.booking_cancelled', [
            'player_id' => $playerId,
            'booking_id' => $bookingId,
        ]);

        return true;
    }
}
