<?php

namespace App\Livewire\Events;

use App\Domain\Event\Models\Event;
use App\Domain\Event\Services\EventRegistrationService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Livewire\Concerns\WithSorting;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
use Symfony\Component\HttpFoundation\StreamedResponse;

#[Layout('layouts.app')]
#[Title('تسجيلات الحدث')]
class EventRegistrationList extends Component
{
    use WithPagination, WithSorting;

    /**
     * Route-model bound, and Event carries BranchScope — another branch's event
     * cannot be resolved here. Locked so the browser cannot swap in a different
     * id after mount() has authorised this one; everything on this screen, the
     * PII export included, hangs off it.
     */
    #[Locked]
    public Event $event;

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

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

    public array $selected = [];
    public bool $selectAll = false;

    public function mount(Event $event): void
    {
        $this->authorize('events.view');
        $this->event = $event->load('cover');
    }

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

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

    public function updatedSelectAll(bool $value): void
    {
        if ($value) {
            $this->selected = $this->event->registrations()
                ->when($this->status, fn ($q) => $q->where('status', $this->status))
                ->pluck('id')
                ->map(fn ($id) => (string) $id)
                ->toArray();
        } else {
            $this->selected = [];
        }
    }

    public function bulkConfirm(EventRegistrationService $service): void
    {
        $this->authorize('events.manage');

        if (empty($this->selected)) {
            return;
        }

        $count = $service->bulkConfirm($this->registrationIdsFromSelection(), auth()->user());
        $this->selected = [];
        $this->selectAll = false;
        session()->flash('success', __("تم تأكيد :count تسجيل", ['count' => $count]));
    }

    public function bulkCancel(EventRegistrationService $service): void
    {
        $this->authorize('events.manage');

        if (empty($this->selected)) {
            return;
        }

        $count = $service->bulkCancel($this->registrationIdsFromSelection(), auth()->user());
        $this->selected = [];
        $this->selectAll = false;
        session()->flash('success', __("تم إلغاء :count تسجيل", ['count' => $count]));
    }

    public function confirm(int $id, EventRegistrationService $service): void
    {
        $this->authorize('events.manage');

        try {
            $registration = $this->event->registrations()->findOrFail($id);
            $service->confirm($registration, auth()->user());
            session()->flash('success', __('تم تأكيد التسجيل'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function cancel(int $id, EventRegistrationService $service): void
    {
        $this->authorize('events.manage');

        try {
            $registration = $this->event->registrations()->findOrFail($id);
            $service->cancel($registration, auth()->user());
            session()->flash('success', __('تم إلغاء التسجيل'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function markAttended(int $id, EventRegistrationService $service): void
    {
        $this->authorize('events.manage');

        try {
            $registration = $this->event->registrations()->findOrFail($id);
            $service->markAttended($registration, auth()->user());
            session()->flash('success', __('تم تسجيل الحضور'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    /**
     * $selected is a checkbox binding, so it is whatever the browser sent.
     * EventRegistrationService::bulkConfirm()/bulkCancel() take bare ids and
     * query them with no event constraint, so resolve them through this event's
     * own relation first: an id that is not a registration of this event simply
     * does not come back.
     */
    private function registrationIdsFromSelection(): array
    {
        return $this->event->registrations()
            ->whereKey($this->selected)
            ->pluck('id')
            ->all();
    }

    public function export(): StreamedResponse
    {
        $this->authorize('events.export');

        $registrations = $this->event->registrations()
            ->when($this->status, fn ($q) => $q->where('status', $this->status))
            ->orderByDesc('created_at')
            ->get();

        $fields = $this->event->form_fields;

        return response()->streamDownload(function () use ($registrations, $fields) {
            $handle = fopen('php://output', 'w');
            fprintf($handle, chr(0xEF) . chr(0xBB) . chr(0xBF));

            $headers = ['#', 'رقم التسجيل', 'الاسم', 'الهاتف', 'البريد', 'الحالة', 'تاريخ التسجيل'];
            foreach ($fields as $field) {
                $headers[] = $field['label'];
            }
            fputcsv($handle, $headers);

            foreach ($registrations as $i => $reg) {
                $statusLabels = [
                    'pending' => 'معلق',
                    'confirmed' => 'مؤكد',
                    'cancelled' => 'ملغي',
                    'attended' => 'حضر',
                    'no_show' => 'لم يحضر',
                ];

                $row = [
                    $i + 1,
                    $reg->registration_number,
                    $reg->registrant_name,
                    $reg->registrant_phone,
                    $reg->registrant_email ?? '-',
                    $statusLabels[$reg->status] ?? $reg->status,
                    $reg->created_at->format('Y-m-d H:i'),
                ];

                foreach ($fields as $field) {
                    $value = $reg->form_data[$field['key']] ?? '-';
                    if (is_array($value)) {
                        $value = implode(', ', $value);
                    }
                    if (is_bool($value)) {
                        $value = $value ? 'نعم' : 'لا';
                    }
                    $row[] = $value;
                }

                fputcsv($handle, $row);
            }

            fclose($handle);
        }, "registrations-{$this->event->slug}.csv", [
            'Content-Type' => 'text/csv; charset=UTF-8',
        ]);
    }

    public function render()
    {
        $query = $this->event->registrations()
            ->when($this->search, function ($q) {
                $q->where(function ($q) {
                    $q->where('registrant_name', 'ilike', "%{$this->search}%")
                      ->orWhere('registrant_phone', 'ilike', "%{$this->search}%")
                      ->orWhere('registrant_email', 'ilike', "%{$this->search}%")
                      ->orWhere('registration_number', 'ilike', "%{$this->search}%");
                });
            })
            ->when($this->status, fn ($q) => $q->where('status', $this->status))
            ->orderBy($this->sortBy, $this->sortDir);

        return view('livewire.events.event-registration-list', [
            'registrations' => $query->paginate(25),
            'formFields' => $this->event->form_fields,
            'statusCounts' => [
                'all' => $this->event->registrations()->count(),
                'pending' => $this->event->registrations()->where('status', 'pending')->count(),
                'confirmed' => $this->event->registrations()->where('status', 'confirmed')->count(),
                'cancelled' => $this->event->registrations()->where('status', 'cancelled')->count(),
                'attended' => $this->event->registrations()->where('status', 'attended')->count(),
            ],
        ]);
    }
}
