<?php

namespace App\Livewire\Enrollments;

use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Enums\EnrollmentStatus;
use App\Domain\Training\Events\WaitlistSpotAvailable;
use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Models\Waitlist;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('قائمة الانتظار')]
class WaitlistManager extends Component
{
    use WithPagination, UsesBranchScope;

    #[Url]
    public string $search = '';

    #[Url]
    public string $groupFilter = '';

    #[Url]
    public string $programFilter = '';

    public function mount(): void
    {
        $this->authorize('enrollments.list');
    }

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function updatedGroupFilter(): void
    {
        $this->resetPage();
    }

    public function updatedProgramFilter(): void
    {
        $this->groupFilter = '';
        $this->resetPage();
    }

    public function promote(int $enrollmentId): void
    {
        $this->authorize('enrollments.update');

        // $enrollmentId is browser-supplied; BranchScope on Enrollment is what
        // keeps another branch's waitlist entry from resolving here.
        $enrollment = Enrollment::where('status', EnrollmentStatus::Waitlisted)->findOrFail($enrollmentId);

        $group = $enrollment->group;

        if (! $group) {
            session()->flash('error', __('المجموعة غير متاحة'));
            return;
        }

        if ($group->isFull()) {
            session()->flash('error', __('المجموعة ممتلئة، لا يمكن الترقية'));
            return;
        }

        $enrollment->update(['status' => 'pending']);

        $group->decrement('waitlist_count');

        // WaitlistSpotAvailable is typed (TrainingGroup, Waitlist). This screen
        // works on waitlisted *enrolments*, so the matching waitlist row has to
        // be resolved before dispatching — passing the Enrollment was a
        // guaranteed TypeError. No row, no notification, but the promotion above
        // still stands.
        $waitlist = Waitlist::where('participant_id', $enrollment->participant_id)
            ->where('training_group_id', $enrollment->training_group_id)
            ->whereNull('response')
            ->orderBy('position')
            ->first();

        if ($waitlist) {
            WaitlistSpotAvailable::dispatch($group, $waitlist);
        }

        session()->flash('success', __('تم ترقية المشترك من قائمة الانتظار بنجاح'));
    }

    public function cancel(int $enrollmentId, string $reason): void
    {
        $this->authorize('enrollments.cancel');

        // Same story as promote(): the branch global scope is the guard on the
        // browser-supplied id.
        $enrollment = Enrollment::where('status', EnrollmentStatus::Waitlisted)->findOrFail($enrollmentId);

        $enrollment->update([
            'status' => 'cancelled',
            'withdrawal_reason' => $reason,
            'withdrawal_date' => now(),
        ]);

        // Update group waitlist count
        if ($enrollment->group) {
            $enrollment->group->decrement('waitlist_count');
        }

        session()->flash('success', __('تم إلغاء التسجيل من قائمة الانتظار'));
    }

    public function render()
    {
        // Enrollment, TrainingGroup and TrainingProgram are all branch-scoped at
        // the model layer, so nothing below repeats the filter. The old
        // whereHas('group', branch_id) also hid every waitlist entry whose group
        // had been soft-deleted, which is not what it was there for.
        $query = Enrollment::query()
            ->where('status', EnrollmentStatus::Waitlisted)
            ->with(['participant.person', 'group', 'program'])
            ->when($this->search, function ($q) {
                $search = $this->search;
                $q->where(function ($q2) use ($search) {
                    $q2->whereHas('participant.person', function ($pq) use ($search) {
                        $pq->where('name_ar', 'ilike', "%{$search}%")
                           ->orWhere('name', 'ilike', "%{$search}%");
                    })->orWhereHas('participant', function ($pq) use ($search) {
                        $pq->where('participant_number', 'ilike', "%{$search}%");
                    });
                });
            })
            ->when($this->groupFilter, fn ($q) => $q->where('training_group_id', $this->groupFilter))
            ->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
            ->orderBy('enrollment_date');

        $groups = TrainingGroup::whereIn('status', ['forming', 'active', 'full'])
            ->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
            ->orderBy('name_ar')
            ->get(['id', 'name_ar', 'current_count', 'max_capacity']);

        return view('livewire.enrollments.waitlist-manager', [
            'enrollments' => $query->paginate(20),
            'groups' => $groups,
            'programs' => TrainingProgram::where('status', 'active')
                ->orderBy('name_ar')
                ->get(['id', 'name_ar']),
        ]);
    }
}
