<?php

namespace App\Livewire\Participants;

use App\Domain\Identity\Models\Guardian;
use App\Domain\Identity\Models\Person;
use App\Domain\Participant\Models\Participant;
use App\Domain\Participant\Services\ParticipantService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\Activity;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('تسجيل مشترك')]
class ParticipantForm extends Component
{
    use UsesBranchScope;

    public ?Participant $participant = null;
    public bool $editing = false;

    // Person fields (for new person creation)
    public ?int $person_id = null;
    public string $name_ar = '';
    public string $name = '';
    public string $national_id = '';
    public ?string $date_of_birth = null;
    public string $gender = 'male';
    public string $phone = '';
    public string $email = '';

    // Participant fields.
    //
    // There is deliberately no $branch_id here. It used to be a plain public
    // property seeded from the session and passed straight to
    // ParticipantService::register — settable from the browser, never
    // re-validated, and the BelongsToBranch creating hook only fills an empty
    // value, so a forged one won. The branch now comes from BranchContext at
    // the moment of the write, where the browser cannot reach it.
    public string $registration_source = 'walk_in';
    public ?int $primary_activity_id = null;
    public ?int $primary_guardian_id = null;
    public ?string $skill_level = null;
    public ?string $membership_type = null;
    public string $membership_id = '';
    public bool $membershipIdSiblingConfirmed = false;
    public array $membershipIdSiblings = [];
    public bool $medical_clearance = false;
    public ?string $medical_clearance_expires = null;
    public ?int $jersey_number = null;
    public string $jersey_size = '';
    public string $shoe_size = '';
    public ?string $dominant_hand = null;
    public ?string $dominant_foot = null;
    public ?string $height_cm = null;
    public ?string $weight_kg = null;
    public string $notes = '';
    public bool $is_free = false;

    // Guardian (editable in edit mode)
    public string $guardian_phone = '';
    public string $new_guardian_name = '';
    public string $new_guardian_phone = '';
    public bool $createNewGuardian = false;

    public function mount(?Participant $participant = null): void
    {
        if ($participant && $participant->exists) {
            $this->participant = $participant->load(['person', 'primaryGuardian.person']);
            $this->editing = true;

            $this->person_id = $participant->person_id;
            $this->name_ar = $participant->person->name_ar ?? '';
            $this->name = $participant->person->name ?? '';
            $this->gender = $participant->person->gender ?? 'male';
            $this->phone = $participant->person->phone ?? '';
            $this->email = $participant->person->email ?? '';
            $this->national_id = $participant->person->national_id ?? '';
            $this->date_of_birth = $participant->person->date_of_birth?->format('Y-m-d');

            $this->registration_source = $participant->registration_source->value ?? $participant->registration_source;
            $this->primary_activity_id = $participant->primary_activity_id;
            $this->primary_guardian_id = $participant->primary_guardian_id;
            $this->skill_level = $participant->skill_level?->value ?? $participant->skill_level;
            $this->membership_type = $participant->membership_type?->value ?? $participant->membership_type;
            $this->membership_id = $participant->membership_id ?? '';
            $this->medical_clearance = $participant->medical_clearance;
            $this->medical_clearance_expires = $participant->medical_clearance_expires?->format('Y-m-d');
            $this->jersey_number = $participant->jersey_number;
            $this->jersey_size = $participant->jersey_size ?? '';
            $this->shoe_size = $participant->shoe_size ?? '';
            $this->dominant_hand = $participant->dominant_hand;
            $this->dominant_foot = $participant->dominant_foot;
            $this->height_cm = $participant->height_cm;
            $this->weight_kg = $participant->weight_kg;
            $this->notes = $participant->notes ?? '';
            $this->is_free = (bool) $participant->is_free;

            // Load guardian phone for editing
            if ($participant->primaryGuardian?->person) {
                $this->guardian_phone = $participant->primaryGuardian->person->phone ?? '';
            }
        }
    }

    private function guardianExistsRule(): \Illuminate\Validation\Rules\Exists
    {
        $branchId = $this->getActiveBranchId();

        return $branchId === null
            ? Rule::exists('guardians', 'id')
            : Rule::exists('guardians', 'id')->where(
                fn ($q) => $q->where('branch_id', $branchId)->orWhereNull('branch_id')
            );
    }

    public function rules(): array
    {
        $rules = [
            'registration_source' => 'required|in:walk_in,online,referral,social_media,event,transfer,other',
            'primary_activity_id' => 'nullable|exists:activities,id',
            // `exists:` is a raw table query, so it never sees the branch
            // global scope, and primary_guardian_id arrives from the browser.
            // guardians is a SHARED table — a null branch is a guardian whose
            // children train at more than one branch, and they must stay
            // linkable from either desk.
            'primary_guardian_id' => ['nullable', $this->guardianExistsRule()],
            'skill_level' => 'nullable|in:beginner,intermediate,advanced,professional',
            'membership_type' => 'nullable|in:member,non_member',
            'membership_id' => $this->membership_type === 'member'
                ? 'required|string|max:50'
                : 'nullable|string|max:50',
            'medical_clearance' => 'boolean',
            'medical_clearance_expires' => 'nullable|date',
            'jersey_number' => 'nullable|integer|min:0|max:999',
            'jersey_size' => 'nullable|string|max:5',
            'shoe_size' => 'nullable|string|max:5',
            'dominant_hand' => 'nullable|in:left,right,both',
            'dominant_foot' => 'nullable|in:left,right,both',
            'height_cm' => 'nullable|numeric|min:50|max:250',
            'weight_kg' => 'nullable|numeric|min:10|max:200',
            'notes' => 'nullable|string',
        ];

        if ($this->editing) {
            $rules['name_ar'] = 'required|string|max:255';
            $rules['name'] = 'nullable|string|max:255';
            $rules['gender'] = 'required|in:male,female';
            $rules['phone'] = 'nullable|string|max:20';
            $rules['email'] = 'nullable|email|max:255';
            $rules['national_id'] = 'nullable|string|max:14';
            $rules['date_of_birth'] = 'nullable|date|before:today';
            $rules['guardian_phone'] = 'nullable|string|max:20';
            if ($this->createNewGuardian) {
                $rules['new_guardian_name'] = 'required|string|max:255';
                $rules['new_guardian_phone'] = 'required|string|max:20';
            }
        } elseif (!$this->person_id) {
            $rules['name_ar'] = 'required|string|max:255';
            $rules['name'] = 'required|string|max:255';
            $rules['gender'] = 'required|in:male,female';
            $rules['phone'] = 'nullable|string|max:20';
            $rules['email'] = 'nullable|email|max:255';
            $rules['national_id'] = 'nullable|string|max:14';
            $rules['date_of_birth'] = 'nullable|date|before:today';
        }

        return $rules;
    }

    public function messages(): array
    {
        return [
            'name_ar.required' => 'الاسم بالعربية مطلوب',
            'name.required' => 'الاسم بالإنجليزية مطلوب',
            'gender.required' => 'الجنس مطلوب',
            'gender.in' => 'الجنس غير صالح',
            'registration_source.required' => 'مصدر التسجيل مطلوب',
            'registration_source.in' => 'مصدر التسجيل غير صالح',
            'skill_level.in' => 'المستوى غير صالح',
            'membership_type.in' => 'نوع العضوية غير صالح',
            'membership_id.required' => 'رقم عضوية النادي مطلوب للأعضاء',
            'membership_id.max' => 'رقم العضوية يجب ألا يتجاوز 50 حرف',
            'dominant_hand.in' => 'اليد المسيطرة غير صالحة',
            'dominant_foot.in' => 'القدم المسيطرة غير صالحة',
            'height_cm.min' => 'الطول يجب أن يكون 50 سم على الأقل',
            'height_cm.max' => 'الطول يجب ألا يتجاوز 250 سم',
            'weight_kg.min' => 'الوزن يجب أن يكون 10 كجم على الأقل',
            'weight_kg.max' => 'الوزن يجب ألا يتجاوز 200 كجم',
            'jersey_number.min' => 'رقم القميص يجب أن يكون 0 أو أكثر',
            'jersey_number.max' => 'رقم القميص يجب ألا يتجاوز 999',
            'medical_clearance_expires.date' => 'تاريخ انتهاء الموافقة الطبية غير صالح',
            'date_of_birth.before' => 'تاريخ الميلاد يجب أن يكون في الماضي',
            'email.email' => 'البريد الإلكتروني غير صالح',
            'new_guardian_name.required' => 'اسم ولي الأمر الجديد مطلوب',
            'new_guardian_phone.required' => 'رقم هاتف ولي الأمر الجديد مطلوب',
        ];
    }

    public function confirmMembershipSibling(): void
    {
        $this->membershipIdSiblingConfirmed = true;
        $this->membershipIdSiblings = [];
    }

    public function cancelMembershipSibling(): void
    {
        $this->membershipIdSiblings = [];
        $this->membership_id = '';
    }

    public function updatedMembershipId(): void
    {
        $this->membershipIdSiblingConfirmed = false;
        $this->membershipIdSiblings = [];
    }

    public function save(ParticipantService $service): void
    {
        $this->validate();

        // Sibling check — warn if membership_id already in use, require confirmation
        if ($this->membership_type === 'member' && $this->membership_id && !$this->membershipIdSiblingConfirmed) {
            // Participant is strictly branch-scoped, so this asks the sibling
            // question for the branch the player is actually in. It used to
            // read the browser-settable $branch_id.
            $existingSiblings = Participant::where('membership_id', $this->membership_id)
                ->when($this->editing, fn ($q) => $q->where('id', '!=', $this->participant->id))
                ->whereNull('deleted_at')
                ->with('person')
                ->get();

            if ($existingSiblings->isNotEmpty()) {
                $this->membershipIdSiblings = $existingSiblings->map(fn ($p) => [
                    'id' => $p->id,
                    'name' => $p->person?->name_ar ?? '-',
                ])->toArray();
                return;
            }
        }

        try {
            if ($this->editing) {
                // Update person data
                $this->participant->person->update([
                    'name_ar' => $this->name_ar,
                    'name' => $this->name ?: $this->name_ar,
                    'gender' => $this->gender,
                    'phone' => $this->phone ?: null,
                    'email' => $this->email ?: null,
                    'national_id' => $this->national_id ?: null,
                    'date_of_birth' => $this->date_of_birth ?: null,
                ]);

                // Handle guardian: create new or update existing phone
                if ($this->createNewGuardian && $this->new_guardian_name) {
                    $guardianPerson = Person::create([
                        'academy_id' => $this->participant->academy_id,
                        'name_ar' => $this->new_guardian_name,
                        'name' => $this->new_guardian_name,
                        'phone' => $this->new_guardian_phone ?: null,
                        'created_by' => auth()->id(),
                    ]);
                    $newGuardian = Guardian::create([
                        'academy_id' => $this->participant->academy_id,
                        'person_id' => $guardianPerson->id,
                        'relationship_type' => 'father',
                        'is_emergency_contact' => true,
                        'is_financial_responsible' => true,
                        'can_pickup' => true,
                    ]);
                    $this->primary_guardian_id = $newGuardian->id;
                } elseif ($this->participant->primaryGuardian?->person && $this->guardian_phone !== '') {
                    $this->participant->primaryGuardian->person->update([
                        'phone' => $this->guardian_phone ?: null,
                    ]);
                }

                $service->update($this->participant, [
                    'primary_activity_id' => $this->primary_activity_id,
                    'primary_guardian_id' => $this->primary_guardian_id,
                    'skill_level' => $this->skill_level,
                    'membership_type' => $this->membership_type ?: null,
                    'membership_id' => $this->membership_type === 'member' ? $this->membership_id : null,
                    'medical_clearance' => $this->medical_clearance,
                    'medical_clearance_expires' => $this->medical_clearance_expires ?: null,
                    'jersey_number' => $this->jersey_number,
                    'jersey_size' => $this->jersey_size ?: null,
                    'shoe_size' => $this->shoe_size ?: null,
                    'dominant_hand' => $this->dominant_hand,
                    'dominant_foot' => $this->dominant_foot,
                    'height_cm' => $this->height_cm ?: null,
                    'weight_kg' => $this->weight_kg ?: null,
                    'notes' => $this->notes ?: null,
                    'is_free' => $this->is_free,
                ], auth()->user());

                session()->flash('success', __('تم تحديث بيانات المشترك بنجاح'));
            } else {
                $data = [
                    // No branch_id: the BelongsToBranch creating hook stamps
                    // the active branch, and ParticipantService falls back to
                    // the academy's main branch when there is none (a public
                    // self-registration). Sending one from here would be
                    // sending whatever the browser last held.
                    'registration_source' => $this->registration_source,
                    'primary_activity_id' => $this->primary_activity_id,
                    'primary_guardian_id' => $this->primary_guardian_id,
                    'skill_level' => $this->skill_level,
                    'membership_type' => $this->membership_type ?: null,
                    'membership_id' => $this->membership_type === 'member' ? $this->membership_id : null,
                    'medical_clearance' => $this->medical_clearance,
                    'medical_clearance_expires' => $this->medical_clearance_expires ?: null,
                    'jersey_number' => $this->jersey_number,
                    'jersey_size' => $this->jersey_size ?: null,
                    'shoe_size' => $this->shoe_size ?: null,
                    'dominant_hand' => $this->dominant_hand,
                    'dominant_foot' => $this->dominant_foot,
                    'height_cm' => $this->height_cm ?: null,
                    'weight_kg' => $this->weight_kg ?: null,
                    'notes' => $this->notes ?: null,
                    'is_free' => $this->is_free,
                ];

                if ($this->person_id) {
                    $data['person_id'] = $this->person_id;
                } else {
                    $data['person'] = [
                        'name_ar' => $this->name_ar,
                        'name' => $this->name ?: $this->name_ar,
                        'national_id' => $this->national_id ?: null,
                        'date_of_birth' => $this->date_of_birth ?: null,
                        'gender' => $this->gender,
                        'phone' => $this->phone ?: null,
                        'email' => $this->email ?: null,
                    ];
                }

                $service->register($data, auth()->user());
                session()->flash('success', __('تم تسجيل المشترك بنجاح'));
            }

            $this->redirect(route('participants.list'), navigate: true);
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function render()
    {
        return view('livewire.participants.participant-form', [
            'activities' => Activity::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
            'guardians' => Guardian::with('person:id,name_ar,phone')->get(),
            'existingPeople' => !$this->editing
                ? Person::whereDoesntHave('participant')
                    ->orderBy('name_ar')
                    ->limit(100)
                    ->get(['id', 'name_ar', 'phone'])
                : collect(),
        ]);
    }
}
