<?php

namespace App\Services;

use App\Models\InternshipBooking;
use App\Models\InternshipBookingParticipant;
use App\Models\MasterData;
use Illuminate\Support\Facades\DB;
use Exception;
use Illuminate\Support\Collection;

class BookingService
{
    /**
     * Memproses booking peserta
     * @param int $leaderId
     * @param int $instansiId
     * @param array $participantIds
     * @throws Exception
     */
    public function createBooking(int $leaderId, int $instansiId, array $participantIds = [])
    {
        // 1. Validasi maksimal peserta (termasuk leader) = 3
        $allUserIds = array_unique(array_merge([$leaderId], $participantIds));
        
        if (count($allUserIds) > 3) {
            throw new Exception("Maksimal peserta dalam satu booking adalah 3 orang.");
        }

        $statusActiveId = MasterData::idFor(MasterData::BOOKING_STATUS, 'active');
        $statusAcceptedId = MasterData::idFor(MasterData::BOOKING_STATUS, 'accepted');

        return DB::transaction(function () use ($allUserIds, $leaderId, $instansiId, $statusActiveId, $statusAcceptedId) {
            
            // 2. Cegah overbooking dan pastikan peserta tidak ada di booking aktif/diterima
            $existingBookings = InternshipBookingParticipant::whereIn('user_id', $allUserIds)
                ->whereHas('booking', function ($query) use ($statusActiveId, $statusAcceptedId) {
                    $query->whereIn('status_id', [$statusActiveId, $statusAcceptedId])
                          ->where('expires_at', '>', now());
                })->lockForUpdate()->get();

            if ($existingBookings->isNotEmpty()) {
                throw new Exception("Salah satu atau lebih peserta sudah memiliki booking yang aktif atau telah diterima.");
            }

            // Validasi Kuota Dinas / Slot Tersedia
            $instansi = \App\Models\Instansi::lockForUpdate()->find($instansiId);
            if (!$instansi) {
                throw new Exception("Dinas/OPD tidak ditemukan.");
            }

            // Hitung peserta yang sedang memiliki booking aktif atau diterima di instansi ini
            $occupiedSlots = \App\Models\InternshipBookingParticipant::whereHas('booking', function ($q) use ($instansiId, $statusActiveId, $statusAcceptedId) {
                $q->where('instansi_id', $instansiId)
                  ->whereIn('status_id', [$statusActiveId, $statusAcceptedId])
                  ->where(function ($subQ) {
                      $subQ->where('expires_at', '>', now())
                           ->orWhereNull('expires_at'); // Bagi yang sudah diterima, expires_at mungkin tidak diandalkan
                  });
            })->count();

            $slotTersedia = max(0, $instansi->kuota - $occupiedSlots);
            
            if ($slotTersedia < count($allUserIds)) {
                throw new Exception("Slot tersedia ({$slotTersedia}) tidak mencukupi untuk jumlah peserta (" . count($allUserIds) . ").");
            }

            // 3. Buat Booking dengan durasi maksimal 1 jam
            $booking = InternshipBooking::create([
                'instansi_id' => $instansiId,
                'leader_id' => $leaderId,
                'status_id' => $statusActiveId,
                'expires_at' => now()->addHour(),
            ]);

            // 4. Masukkan Partisipan
            foreach ($allUserIds as $userId) {
                InternshipBookingParticipant::create([
                    'booking_id' => $booking->id,
                    'user_id' => $userId,
                ]);
            }

            return $booking;
        });
    }

    /**
     * Memeriksa dan membatalkan booking yang kedaluwarsa
     */
    public function expireOldBookings()
    {
        $statusActiveId = MasterData::idFor(MasterData::BOOKING_STATUS, 'active');
        $statusExpiredId = MasterData::idFor(MasterData::BOOKING_STATUS, 'expired');

        $expiredBookings = InternshipBooking::where('status_id', $statusActiveId)
            ->where('expires_at', '<', now())
            ->get();

        foreach ($expiredBookings as $booking) {
            $booking->update(['status_id' => $statusExpiredId]);
            // Slot akan otomatis dilepas karena tidak dihitung dalam query "booking aktif" lagi.
        }
    }
}
