<?php

namespace App\Domain\Event\Services;

use App\Domain\Event\Enums\FormFieldType;
use App\Domain\Event\Enums\RegistrationStatus;
use App\Domain\Event\Models\Event;
use App\Domain\Event\Models\EventRegistration;
use App\Domain\Identity\Models\Person;
use App\Domain\Shared\Exceptions\DomainException;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class EventRegistrationService
{
    public function register(Event $event, array $formData, array $meta): EventRegistration
    {
        if (! $event->isRegistrationOpen()) {
            throw new DomainException('التسجيل مغلق لهذا الحدث');
        }

        if (! $event->hasCapacity()) {
            throw new DomainException('تم اكتمال العدد المسموح به');
        }

        return DB::transaction(function () use ($event, $formData, $meta) {
            $personId = $this->matchPerson($meta['phone'], $meta['email'] ?? null, $event->academy_id);

            $registration = EventRegistration::create([
                'academy_id' => $event->academy_id,
                'event_id' => $event->id,
                'person_id' => $personId,
                'registration_number' => $this->generateRegistrationNumber($event),
                'status' => 'pending',
                'form_data' => $formData,
                'registrant_name' => $meta['name'],
                'registrant_phone' => $meta['phone'],
                'registrant_email' => $meta['email'] ?? null,
                'ip_address' => $meta['ip'] ?? null,
            ]);

            $event->increment('registrations_count');

            return $registration;
        });
    }

    public function confirm(EventRegistration $registration, User $admin): EventRegistration
    {
        if ($registration->status !== RegistrationStatus::Pending) {
            throw new DomainException('لا يمكن تأكيد هذا التسجيل');
        }

        $registration->update([
            'status' => 'confirmed',
            'confirmed_at' => now(),
        ]);

        return $registration->fresh();
    }

    public function cancel(EventRegistration $registration, User $admin, ?string $reason = null): EventRegistration
    {
        if (in_array($registration->status, [RegistrationStatus::Cancelled, RegistrationStatus::Attended])) {
            throw new DomainException('لا يمكن إلغاء هذا التسجيل');
        }

        DB::transaction(function () use ($registration, $reason) {
            $registration->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
                'admin_notes' => $reason ? ($registration->admin_notes ? $registration->admin_notes . "\n" : '') . "سبب الإلغاء: {$reason}" : $registration->admin_notes,
            ]);

            $registration->event->decrement('registrations_count');
        });

        return $registration->fresh();
    }

    public function markAttended(EventRegistration $registration, User $admin): EventRegistration
    {
        if ($registration->status === RegistrationStatus::Cancelled) {
            throw new DomainException('لا يمكن تسجيل حضور تسجيل ملغي');
        }

        $registration->update([
            'status' => 'attended',
            'attended_at' => now(),
        ]);

        return $registration->fresh();
    }

    public function bulkConfirm(array $ids, User $admin): int
    {
        $count = 0;
        $registrations = EventRegistration::whereIn('id', $ids)->where('status', 'pending')->get();

        foreach ($registrations as $reg) {
            $this->confirm($reg, $admin);
            $count++;
        }

        return $count;
    }

    public function bulkCancel(array $ids, User $admin): int
    {
        $count = 0;
        $registrations = EventRegistration::whereIn('id', $ids)
            ->whereNotIn('status', ['cancelled', 'attended'])
            ->get();

        foreach ($registrations as $reg) {
            $this->cancel($reg, $admin);
            $count++;
        }

        return $count;
    }

    public function validateFormData(Event $event, array $submitted): array
    {
        $rules = [];
        $messages = [];

        foreach ($event->form_fields as $field) {
            $key = "fields.{$field['key']}";
            $fieldRules = [];

            if ($field['is_required']) {
                $fieldRules[] = 'required';
                $messages["{$key}.required"] = "حقل {$field['label']} مطلوب";
            } else {
                $fieldRules[] = 'nullable';
            }

            $type = FormFieldType::tryFrom($field['type']);
            if ($type) {
                foreach (explode('|', $type->baseValidation()) as $rule) {
                    $fieldRules[] = $rule;
                }
            }

            if (in_array($field['type'], ['select']) && ! empty($field['options'])) {
                $values = array_column($field['options'], 'value');
                $fieldRules[] = 'in:' . implode(',', $values);
            }

            $rules[$key] = implode('|', $fieldRules);
        }

        return ['rules' => $rules, 'messages' => $messages];
    }

    public function matchPerson(string $phone, ?string $email, int $academyId): ?int
    {
        $person = Person::withoutGlobalScopes()
            ->where('academy_id', $academyId)
            ->where(function ($q) use ($phone, $email) {
                $q->where('phone', $phone);
                if ($email) {
                    $q->orWhere('email', $email);
                }
            })
            ->first();

        return $person?->id;
    }

    public function generateRegistrationNumber(Event $event): string
    {
        $prefix = 'EVT-' . now()->format('ym');
        $lastNumber = EventRegistration::withoutGlobalScopes()
            ->where('academy_id', $event->academy_id)
            ->where('registration_number', 'like', $prefix . '%')
            ->max('registration_number');

        if ($lastNumber) {
            $seq = (int) substr($lastNumber, -4) + 1;
        } else {
            $seq = 1;
        }

        return $prefix . '-' . str_pad($seq, 4, '0', STR_PAD_LEFT);
    }
}
