<?php

namespace App\Livewire\Facilities;

use App\Domain\Facility\Models\Facility;
use App\Domain\Facility\Models\SpaceLayout;
use App\Domain\Facility\Models\SpaceReservation;
use App\Domain\Facility\Models\SpaceSegment;
use App\Domain\Facility\Services\SpaceCollisionService;
use App\Domain\Facility\Services\SpaceLayoutService;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingSchedule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('تعيين المجموعات على الملاعب')]
class SpaceAssignmentWizard extends Component
{
    use UsesBranchScope;

    public int $step = 1;

    // Step 1: Select Group
    public string $groupSearch = '';
    public ?int $selectedGroupId = null;
    public ?array $selectedGroup = null;

    // Step 2: Select Schedule
    public ?int $selectedScheduleId = null;
    public array $schedules = [];

    // Step 3: Select Facility
    public ?int $selectedFacilityId = null;
    public array $facilities = [];

    // Step 4: Visual Grid Selection
    public ?int $resolvedLayoutId = null;
    public array $segments = [];
    public array $selectedSegmentIds = [];
    public array $occupiedSegments = [];
    public array $conflicts = [];
    public array $warnings = [];

    // Layout info
    public string $layoutType = 'grid';
    public int $gridRows = 0;
    public int $gridCols = 0;

    public function mount(): void
    {
        $this->authorize('facilities.manage_layouts');
        $this->facilities = Facility::where('status', 'active')
            ->when($this->getActiveBranchId(), fn ($q) => $q->where('branch_id', $this->getActiveBranchId()))
            ->orderBy('name_ar')
            ->get(['id', 'name', 'name_ar', 'type'])
            ->toArray();
    }

    public function updatedGroupSearch(): void
    {
        // Search is handled in render()
    }

    public function selectGroup(int $id): void
    {
        $group = TrainingGroup::with(['program', 'schedules.trainer'])->findOrFail($id);
        $this->selectedGroupId = $id;
        $this->selectedGroup = [
            'id' => $group->id,
            'name_ar' => $group->name_ar,
            'name' => $group->name,
            'program_name' => $group->program?->name_ar ?? '-',
            'current_count' => $group->current_count,
            'max_capacity' => $group->max_capacity,
        ];

        $this->schedules = $group->schedules
            ->map(fn ($s) => [
                'id' => $s->id,
                'day_of_week' => $s->day_of_week,
                'day_name' => $s->day_name,
                'start_time' => $s->start_time,
                'end_time' => $s->end_time,
                'trainer_name' => $s->trainer?->name_ar ?? '-',
                'facility_id' => $s->facility_id,
                'has_space_template' => !empty($s->space_reservation_template),
            ])
            ->toArray();

        $this->step = 2;
    }

    public function selectSchedule(int $id): void
    {
        $this->selectedScheduleId = $id;
        $schedule = TrainingSchedule::findOrFail($id);

        if ($schedule->facility_id) {
            $this->selectedFacilityId = $schedule->facility_id;
            $this->selectedSegmentIds = $schedule->space_reservation_template ?? [];
            $this->step = 4;
            $this->resolveLayout();
        } else {
            $this->step = 3;
        }
    }

    public function selectFacility(int $id): void
    {
        $this->selectedFacilityId = $id;
        $this->step = 4;
        $this->resolveLayout();
    }

    public function resolveLayout(): void
    {
        if (!$this->selectedFacilityId || !$this->selectedScheduleId) {
            return;
        }

        $schedule = TrainingSchedule::findOrFail($this->selectedScheduleId);

        $layoutService = app(SpaceLayoutService::class);
        $today = now()->toDateString();
        $layout = $layoutService->resolveLayout(
            $this->selectedFacilityId,
            $today,
            $schedule->start_time
        );

        if (!$layout) {
            $layout = SpaceLayout::where('facility_id', $this->selectedFacilityId)
                ->where('is_active', true)
                ->where('is_recurring', true)
                ->where('effective_day_of_week', $schedule->day_of_week)
                ->first();
        }

        if (!$layout) {
            $layout = SpaceLayout::where('facility_id', $this->selectedFacilityId)
                ->where('is_active', true)
                ->first();
        }

        if (!$layout) {
            $this->segments = [];
            $this->resolvedLayoutId = null;
            return;
        }

        $this->resolvedLayoutId = $layout->id;
        $this->layoutType = $layout->layout_type->value;

        $config = $layout->layout_config;
        $this->gridRows = $config['rows'] ?? 0;
        $this->gridCols = $config['columns'] ?? 0;

        $this->segments = $layout->segments()
            ->orderBy('sort_order')
            ->get(['id', 'code', 'name', 'name_ar', 'row_index', 'col_index', 'lane_number', 'is_available', 'capacity'])
            ->toArray();

        $this->loadOccupiedSegments($schedule);
    }

    private function loadOccupiedSegments(TrainingSchedule $schedule): void
    {
        $nextDate = $this->getNextOccurrenceDate($schedule->day_of_week);

        $reservations = SpaceReservation::where('facility_id', $this->selectedFacilityId)
            ->where('reservation_date', $nextDate)
            ->where('status', 'confirmed')
            ->where('start_time', '<', $schedule->end_time)
            ->where('end_time', '>', $schedule->start_time)
            ->get();

        $this->occupiedSegments = [];
        foreach ($reservations as $res) {
            foreach ($res->segment_ids ?? [] as $segId) {
                $this->occupiedSegments[$segId] = [
                    'reservation_id' => $res->id,
                    'title' => $res->title ?? $res->notes ?? __('محجوز'),
                ];
            }
        }
    }

    private function getNextOccurrenceDate(int $dayOfWeek): string
    {
        $today = now();
        $currentDay = (int) $today->format('w');
        $diff = $dayOfWeek - $currentDay;
        if ($diff <= 0) {
            $diff += 7;
        }
        return $today->addDays($diff)->toDateString();
    }

    public function toggleSegment(int $segmentId): void
    {
        if (isset($this->occupiedSegments[$segmentId])) {
            return;
        }

        $segment = collect($this->segments)->firstWhere('id', $segmentId);
        if ($segment && !$segment['is_available']) {
            return;
        }

        if (in_array($segmentId, $this->selectedSegmentIds)) {
            $this->selectedSegmentIds = array_values(array_diff($this->selectedSegmentIds, [$segmentId]));
        } else {
            $this->selectedSegmentIds[] = $segmentId;
        }

        $this->checkConflicts();
    }

    public function selectAll(): void
    {
        $this->selectedSegmentIds = collect($this->segments)
            ->filter(fn ($s) => $s['is_available'] && !isset($this->occupiedSegments[$s['id']]))
            ->pluck('id')
            ->toArray();
        $this->checkConflicts();
    }

    public function clearSelection(): void
    {
        $this->selectedSegmentIds = [];
        $this->conflicts = [];
        $this->warnings = [];
    }

    private function checkConflicts(): void
    {
        if (empty($this->selectedSegmentIds) || !$this->selectedScheduleId) {
            $this->conflicts = [];
            $this->warnings = [];
            return;
        }

        $schedule = TrainingSchedule::findOrFail($this->selectedScheduleId);
        $nextDate = $this->getNextOccurrenceDate($schedule->day_of_week);
        $collisionService = app(SpaceCollisionService::class);

        $this->conflicts = $collisionService->check(
            $this->selectedFacilityId,
            $nextDate,
            $schedule->start_time,
            $schedule->end_time,
            $this->selectedSegmentIds
        );

        $this->warnings = $collisionService->getTentativeWarnings(
            $this->selectedFacilityId,
            $nextDate,
            $schedule->start_time,
            $schedule->end_time,
            $this->selectedSegmentIds
        );
    }

    public function saveAssignment(): void
    {
        if (empty($this->selectedSegmentIds)) {
            session()->flash('error', __('يرجى اختيار مساحة واحدة على الأقل'));
            return;
        }

        if (!empty($this->conflicts)) {
            session()->flash('error', __('يوجد تعارض مع حجوزات مؤكدة. يرجى إزالة التعارض أولاً'));
            return;
        }

        $schedule = TrainingSchedule::findOrFail($this->selectedScheduleId);
        $schedule->update([
            'facility_id' => $this->selectedFacilityId,
            'space_reservation_template' => $this->selectedSegmentIds,
        ]);

        session()->flash('success', __('تم تعيين المساحة للمجموعة بنجاح! سيتم حجز المساحة تلقائياً عند إنشاء الحصص.'));
        $this->step = 5;
    }

    public function goToStep(int $step): void
    {
        if ($step < $this->step) {
            $this->step = $step;
        }
    }

    public function startOver(): void
    {
        $this->reset();
        $this->mount();
        $this->step = 1;
    }

    public function render()
    {
        $searchResults = collect();
        if (strlen($this->groupSearch) >= 2) {
            $searchResults = TrainingGroup::with('program')
                ->when($this->getActiveBranchId(), fn ($q) => $q->where('branch_id', $this->getActiveBranchId()))
                ->where(function ($q) {
                    $q->where('name_ar', 'ilike', "%{$this->groupSearch}%")
                      ->orWhere('name', 'ilike', "%{$this->groupSearch}%")
                      ->orWhere('code', 'ilike', "%{$this->groupSearch}%");
                })
                ->where('status', 'active')
                ->limit(10)
                ->get();
        }

        $facilityType = collect($this->facilities)->firstWhere('id', $this->selectedFacilityId)['type'] ?? 'other';

        return view('livewire.facilities.space-assignment-wizard', [
            'searchResults' => $searchResults,
            'facilityType' => $facilityType,
        ]);
    }
}
