<?php

namespace App\Domain\Facility\Services;

use App\Domain\Facility\Enums\FacilityStatus;
use App\Domain\Facility\Enums\ReservationStatus;
use App\Domain\Facility\Models\Facility;
use App\Domain\Facility\Models\SpaceReservation;
use App\Domain\Facility\Models\SpaceSegment;
use App\Domain\Shared\Exceptions\DomainException;

class SpaceCollisionService
{
    /**
     * Check for confirmed reservation collisions.
     *
     * Returns array of conflicts (empty = no collision).
     */
    public function check(
        int $facilityId,
        string $date,
        string $startTime,
        string $endTime,
        array $segmentIds,
        ?int $excludeId = null
    ): array {
        // 1. Find confirmed reservations for facility on date that overlap in time
        $query = SpaceReservation::where('facility_id', $facilityId)
            ->where('reservation_date', $date)
            ->where('status', ReservationStatus::Confirmed)
            ->where('start_time', '<', $endTime)
            ->where('end_time', '>', $startTime);

        // 3. Exclude self (if editing)
        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        $overlapping = $query->get();

        if ($overlapping->isEmpty()) {
            return [];
        }

        // 4-5. Decode segments JSON and intersect with requested
        $conflicts = [];
        foreach ($overlapping as $reservation) {
            $occupiedSegments = $reservation->segment_ids ?? [];
            $intersection = array_intersect($segmentIds, $occupiedSegments);

            // 6-7. Non-empty intersection = conflict
            if (!empty($intersection)) {
                $conflicts[] = [
                    'reservation_id' => $reservation->id,
                    'title' => $reservation->title,
                    'time' => $reservation->start_time . ' - ' . $reservation->end_time,
                    'conflicting_segments' => array_values($intersection),
                ];
            }
        }

        return $conflicts;
    }

    /**
     * Get tentative reservation warnings (non-blocking).
     */
    public function getTentativeWarnings(
        int $facilityId,
        string $date,
        string $startTime,
        string $endTime,
        array $segmentIds
    ): array {
        $query = SpaceReservation::where('facility_id', $facilityId)
            ->where('reservation_date', $date)
            ->where('status', ReservationStatus::Tentative)
            ->where('start_time', '<', $endTime)
            ->where('end_time', '>', $startTime);

        $overlapping = $query->get();
        $warnings = [];

        foreach ($overlapping as $reservation) {
            $occupiedSegments = $reservation->segment_ids ?? [];
            $intersection = array_intersect($segmentIds, $occupiedSegments);

            if (!empty($intersection)) {
                $warnings[] = [
                    'reservation_id' => $reservation->id,
                    'title' => $reservation->title,
                    'time' => $reservation->start_time . ' - ' . $reservation->end_time,
                    'conflicting_segments' => array_values($intersection),
                ];
            }
        }

        return $warnings;
    }

    /**
     * Validate that all requested segments are marked as available.
     */
    public function validateSegmentsAvailable(array $segmentIds): void
    {
        $unavailable = SpaceSegment::whereIn('id', $segmentIds)
            ->where('is_available', false)
            ->pluck('name_ar');

        if ($unavailable->isNotEmpty()) {
            throw new DomainException('الأجزاء التالية غير متاحة: ' . $unavailable->implode(', '));
        }
    }

    /**
     * Validate that the facility is active and the time is within operating hours.
     */
    public function validateFacilityCanBeReserved(Facility $facility, string $startTime, string $endTime): void
    {
        if ($facility->status !== FacilityStatus::Active) {
            throw new DomainException('المنشأة غير نشطة حالياً: ' . $facility->status->label());
        }

        if ($facility->operating_start && $startTime < $facility->operating_start) {
            throw new DomainException('وقت البداية قبل ساعات العمل (' . $facility->operating_start . ')');
        }

        if ($facility->operating_end && $endTime > $facility->operating_end) {
            throw new DomainException('وقت النهاية بعد ساعات العمل (' . $facility->operating_end . ')');
        }
    }
}
