<?php

namespace App\Livewire\Users;

use App\Domain\HR\Enums\CompensationModel;
use App\Domain\HR\Enums\EmploymentType;
use App\Domain\HR\Models\Employee;
use App\Domain\HR\Models\Trainer;
use App\Domain\HR\Services\EmployeeService;
use App\Domain\HR\Services\TrainerService;
use App\Domain\Identity\Models\Branch;
use App\Domain\Identity\Models\Guardian;
use App\Domain\Identity\Models\Person;
use App\Domain\Identity\Models\Role;
use App\Domain\Participant\Models\Participant;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('إدارة المستخدم')]
class UserForm extends Component
{
    public ?User $user = null;
    public bool $editing = false;

    // ─── User Fields ─────────────────────────────────────────────
    public string $name = '';
    public string $name_ar = '';
    public string $email = '';
    public string $password = '';
    public string $password_confirmation = '';
    public ?int $role_id = null;
    public ?int $person_id = null;
    public string $status = 'active';

    // ─── Role-Aware: Selected role slug (computed from role_id) ──
    public string $selectedRoleSlug = '';

    // ─── Trainer Setup Fields ────────────────────────────────────
    public bool $createTrainer = true;
    public string $trainerCompensationModel = 'per_session';
    public string $trainerRateAmount = '';
    public ?int $trainerBranchId = null;

    // ─── Employee Setup Fields ───────────────────────────────────
    public bool $createEmployee = true;
    public string $employeeDepartment = '';
    public string $employeePosition = '';
    public string $employeeEmploymentType = 'full_time';
    public ?int $employeeBranchId = null;
    public string $employeeStartDate = '';

    // ─── Guardian Setup Fields ───────────────────────────────────
    public string $guardianMode = 'new'; // 'new' or 'existing'
    public ?int $existingGuardianId = null;
    public string $guardianRelationshipType = 'father';
    public array $guardianParticipantIds = [];

    // ─── State Tracking ──────────────────────────────────────────
    public bool $roleChanged = false;
    public bool $hasExistingTrainer = false;
    public bool $hasExistingEmployee = false;
    public bool $hasExistingGuardian = false;
    public bool $missingRoleEntities = false;

    public function mount(?User $user = null): void
    {
        if ($user && $user->exists) {
            $this->authorize('users.update');
            $this->user = $user;
            $this->editing = true;
            $this->name = $user->name;
            $this->name_ar = $user->name_ar ?? '';
            $this->email = $user->email;
            $this->role_id = $user->role_id;
            $this->person_id = $user->person_id;
            $this->status = $user->status ?? 'active';
            $this->resolveRoleSlug();
            $this->detectExistingEntities();
        } else {
            $this->authorize('users.create');
            $this->employeeStartDate = now()->toDateString();
        }
    }

    private function detectExistingEntities(): void
    {
        $person = $this->user->person;

        if ($person) {
            $this->hasExistingEmployee = Employee::where('person_id', $person->id)->exists();
            $this->hasExistingTrainer = Trainer::where('person_id', $person->id)
                ->orWhere(function ($q) use ($person) {
                    $employee = Employee::where('person_id', $person->id)->first();
                    if ($employee) {
                        $q->where('employee_id', $employee->id);
                    }
                })->exists();
            $this->hasExistingGuardian = Guardian::where('person_id', $person->id)->exists();
        }

        // Detect orphan state: role says trainer but no trainer record
        if ($this->shouldShowTrainerSection() && !$this->hasExistingTrainer) {
            $this->missingRoleEntities = true;
            $this->createTrainer = true;
        } elseif ($this->shouldShowTrainerSection()) {
            $this->createTrainer = false;
        }

        if ($this->shouldShowGuardianSection() && !$this->hasExistingGuardian) {
            $this->missingRoleEntities = true;
        }

        if ($this->shouldShowEmployeeSection() && !$this->hasExistingEmployee) {
            $this->missingRoleEntities = true;
            $this->createEmployee = true;
        } elseif ($this->shouldShowEmployeeSection()) {
            $this->createEmployee = false;
        }
    }

    public function updatedRoleId(): void
    {
        $this->resolveRoleSlug();
        $this->roleChanged = true;
    }

    private function resolveRoleSlug(): void
    {
        if ($this->role_id) {
            $this->selectedRoleSlug = Role::find($this->role_id)?->slug ?? '';
        } else {
            $this->selectedRoleSlug = '';
        }
    }

    public function rules(): array
    {
        $rules = [
            'name' => 'required|string|max:255',
            'name_ar' => 'required|string|max:255',
            'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')->ignore($this->user?->id)],
            'role_id' => 'nullable|exists:roles,id',
            'person_id' => 'nullable|exists:people,id',
            'status' => 'required|in:active,inactive,suspended,pending',
        ];

        if (! $this->editing) {
            $rules['password'] = 'required|string|min:8|confirmed';
        } else {
            $rules['password'] = 'nullable|string|min:8|confirmed';
        }

        // Trainer-specific rules
        if ($this->shouldShowTrainerSection() && $this->createTrainer) {
            $rules['trainerCompensationModel'] = 'required|in:salary,hourly,per_session,per_group,per_player,revenue_share,contract,hybrid';
            $rules['trainerRateAmount'] = 'required|numeric|min:0';
            $rules['trainerBranchId'] = 'nullable|exists:branches,id';
        }

        // Employee-specific rules (for staff roles)
        if ($this->shouldShowEmployeeSection() && $this->createEmployee) {
            $rules['employeeEmploymentType'] = 'required|in:full_time,part_time,contract,intern,volunteer';
            $rules['employeeBranchId'] = 'nullable|exists:branches,id';
            $rules['employeeStartDate'] = 'required|date';
        }

        // Guardian-specific rules
        if ($this->shouldShowGuardianSection()) {
            if ($this->guardianMode === 'existing') {
                $rules['existingGuardianId'] = 'required|exists:guardians,id';
            } else {
                $rules['guardianRelationshipType'] = 'required|in:father,mother,grandfather,grandmother,uncle,aunt,sibling,legal_guardian,other';
            }
        }

        return $rules;
    }

    public function messages(): array
    {
        return [
            'name.required' => 'الاسم بالإنجليزية مطلوب',
            'name_ar.required' => 'الاسم بالعربية مطلوب',
            'email.required' => 'البريد الإلكتروني مطلوب',
            'email.email' => 'صيغة البريد الإلكتروني غير صحيحة',
            'email.unique' => 'البريد الإلكتروني مستخدم بالفعل',
            'password.required' => 'كلمة المرور مطلوبة',
            'password.min' => 'كلمة المرور يجب أن تكون 8 أحرف على الأقل',
            'password.confirmed' => 'تأكيد كلمة المرور غير متطابق',
            'trainerCompensationModel.required' => 'نموذج التعويض مطلوب',
            'trainerRateAmount.required' => 'قيمة المعدل مطلوبة',
            'trainerRateAmount.numeric' => 'قيمة المعدل يجب أن تكون رقماً',
            'employeeEmploymentType.required' => 'نوع التوظيف مطلوب',
            'employeeStartDate.required' => 'تاريخ البدء مطلوب',
            'existingGuardianId.required' => 'يجب اختيار ولي أمر',
            'guardianRelationshipType.required' => 'نوع العلاقة مطلوب',
        ];
    }

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

        if ($this->role_id) {
            $targetRole = Role::find($this->role_id);
            $currentUserLevel = auth()->user()->primaryRole?->level ?? 0;
            if ($targetRole && $targetRole->level >= $currentUserLevel && ! auth()->user()->is_super_admin) {
                $this->addError('role_id', 'لا يمكنك تعيين دور بمستوى أعلى من أو يساوي مستواك');
                return;
            }
        }

        try {
            DB::transaction(function () {
                $academyId = app('current_academy')->id;
                $actor = auth()->user();

                // Create or get Person record
                $person = $this->resolveOrCreatePerson($academyId, $actor);

                // Build user data
                $data = [
                    'name' => $this->name,
                    'name_ar' => $this->name_ar,
                    'email' => $this->email,
                    'role_id' => $this->role_id,
                    'person_id' => $person?->id ?? $this->person_id,
                    'status' => $this->status,
                ];

                if ($this->password) {
                    $data['password'] = Hash::make($this->password);
                }

                if ($this->editing) {
                    $this->user->update($data);
                    $user = $this->user;
                } else {
                    $data['academy_id'] = $academyId;
                    $user = User::create($data);
                }

                // Link person to user
                if ($person && ! $person->user_id) {
                    $person->update(['user_id' => $user->id]);
                }

                // Handle role-specific entity creation
                $this->handleRoleEntities($user, $person, $academyId, $actor);
            });

            session()->flash('success', $this->editing ? 'تم تحديث المستخدم بنجاح' : 'تم إنشاء المستخدم بنجاح');
        } catch (\Throwable $e) {
            session()->flash('error', 'حدث خطأ: ' . $e->getMessage());
            return;
        }

        $this->redirect(route('users.list'), navigate: true);
    }

    private function resolveOrCreatePerson(int $academyId, User $actor): ?Person
    {
        // If person_id already selected, use it
        if ($this->person_id) {
            return Person::find($this->person_id);
        }

        // For roles that need a person record, create one
        if ($this->needsPersonRecord()) {
            return Person::create([
                'academy_id' => $academyId,
                'name' => $this->name,
                'name_ar' => $this->name_ar,
                'email' => $this->email,
                'created_by' => $actor->id,
            ]);
        }

        return null;
    }

    private function needsPersonRecord(): bool
    {
        if ($this->selectedRoleSlug === 'trainer' || $this->selectedRoleSlug === 'head_trainer') {
            return $this->createTrainer;
        }

        if ($this->selectedRoleSlug === 'parent') {
            return $this->guardianMode === 'new';
        }

        if (in_array($this->selectedRoleSlug, ['receptionist', 'accountant', 'branch_manager', 'academy_admin'])) {
            return $this->createEmployee;
        }

        return false;
    }

    private function handleRoleEntities(User $user, ?Person $person, int $academyId, User $actor): void
    {
        // Process for: new users, role changes, or missing entity repair
        if ($this->editing && ! $this->roleChanged && ! $this->missingRoleEntities) {
            return;
        }

        if ($this->shouldShowTrainerSection() && $this->createTrainer) {
            $this->createTrainerEntities($user, $person, $academyId, $actor);
        } elseif ($this->shouldShowGuardianSection()) {
            $this->createGuardianEntities($user, $person, $academyId);
        } elseif ($this->shouldShowEmployeeSection() && $this->createEmployee) {
            $this->createEmployeeEntity($user, $person, $academyId, $actor);
        }
    }

    private function createTrainerEntities(User $user, ?Person $person, int $academyId, User $actor): void
    {
        if (! $person) {
            return;
        }

        // Check if employee already exists for this person
        $employee = Employee::where('person_id', $person->id)->first();

        if (! $employee) {
            $employeeService = app(EmployeeService::class);
            $employee = $employeeService->create([
                'academy_id' => $academyId,
                'person_id' => $person->id,
                'user_id' => $user->id,
                'employment_type' => 'full_time',
                'start_date' => now()->toDateString(),
                'department' => 'التدريب',
                'position' => 'مدرب',
                'branch_id' => $this->trainerBranchId,
                'status' => 'active',
            ], $actor);
        } else {
            // Ensure user_id is linked
            if (! $employee->user_id) {
                $employee->update(['user_id' => $user->id]);
            }
        }

        // Check if trainer record already exists
        $existingTrainer = Trainer::where('employee_id', $employee->id)->first();
        if (! $existingTrainer) {
            $trainerService = app(TrainerService::class);
            $rateField = $this->getRateFieldForCompensation($this->trainerCompensationModel);
            $rateInPiasters = (int) round((float) $this->trainerRateAmount * 100);

            $trainerData = [
                'compensation_model' => $this->trainerCompensationModel,
                'person_id' => $person->id,
                'status' => 'active',
            ];

            if ($rateField) {
                $trainerData[$rateField] = $rateInPiasters;
            }

            $trainerService->create($employee, $trainerData, $actor);
        }
    }

    private function createGuardianEntities(User $user, ?Person $person, int $academyId): void
    {
        if ($this->guardianMode === 'existing' && $this->existingGuardianId) {
            // Link existing guardian to this user
            $guardian = Guardian::find($this->existingGuardianId);
            if ($guardian && ! $guardian->user_id) {
                $guardian->update(['user_id' => $user->id]);
            }
        } elseif ($this->guardianMode === 'new' && $person) {
            // Create new guardian record
            $guardian = Guardian::create([
                'academy_id' => $academyId,
                'person_id' => $person->id,
                'user_id' => $user->id,
                'relationship_type' => $this->guardianRelationshipType,
                'is_financial_responsible' => true,
            ]);

            // Link to selected participants
            if (! empty($this->guardianParticipantIds)) {
                foreach ($this->guardianParticipantIds as $participantId) {
                    $guardian->participants()->attach($participantId, [
                        'relationship_type' => $this->guardianRelationshipType,
                        'is_primary' => true,
                        'receives_notifications' => true,
                        'can_pickup' => true,
                    ]);
                }
            }
        }
    }

    private function createEmployeeEntity(User $user, ?Person $person, int $academyId, User $actor): void
    {
        if (! $person) {
            return;
        }

        // Check if employee already exists
        $existing = Employee::where('person_id', $person->id)->first();
        if ($existing) {
            if (! $existing->user_id) {
                $existing->update(['user_id' => $user->id]);
            }
            return;
        }

        $employeeService = app(EmployeeService::class);
        $employeeService->create([
            'academy_id' => $academyId,
            'person_id' => $person->id,
            'user_id' => $user->id,
            'employment_type' => $this->employeeEmploymentType,
            'start_date' => $this->employeeStartDate ?: now()->toDateString(),
            'department' => $this->employeeDepartment ?: null,
            'position' => $this->employeePosition ?: null,
            'branch_id' => $this->employeeBranchId,
            'status' => 'active',
        ], $actor);
    }

    private function getRateFieldForCompensation(string $model): ?string
    {
        return match ($model) {
            'hourly' => 'hourly_rate',
            'per_session' => 'session_rate',
            'per_group' => 'group_rate',
            'per_player' => 'player_rate',
            default => 'session_rate',
        };
    }

    // ─── Section Visibility Helpers ──────────────────────────────

    public function shouldShowTrainerSection(): bool
    {
        return in_array($this->selectedRoleSlug, ['trainer', 'head_trainer']);
    }

    public function shouldShowGuardianSection(): bool
    {
        return $this->selectedRoleSlug === 'parent';
    }

    public function shouldShowEmployeeSection(): bool
    {
        return in_array($this->selectedRoleSlug, ['receptionist', 'accountant', 'branch_manager', 'academy_admin']);
    }

    public function render()
    {
        $rolesQuery = Role::orderBy('level', 'desc');

        if (! auth()->user()->is_super_admin) {
            $currentUserLevel = auth()->user()->primaryRole?->level ?? 0;
            $rolesQuery->where('level', '<', $currentUserLevel);
        }

        $viewData = [
            'roles' => $rolesQuery->get(['id', 'name_ar', 'slug', 'level']),
            'people' => Person::orderBy('name_ar')
                ->get(['id', 'name_ar'])
                ->map(fn ($p) => ['id' => $p->id, 'name' => $p->name_ar]),
            'branches' => Branch::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
            'compensationModels' => CompensationModel::cases(),
            'employmentTypes' => EmploymentType::cases(),
        ];

        // Load guardians list for parent role
        if ($this->shouldShowGuardianSection()) {
            $viewData['guardians'] = Guardian::with('person')
                ->orderBy('id', 'desc')
                ->get()
                ->map(fn ($g) => [
                    'id' => $g->id,
                    'name' => $g->person?->name_ar ?? __('بدون اسم'),
                    'phone' => $g->person?->phone ?? '',
                ]);

            $viewData['participants'] = Participant::with('person')
                ->orderBy('id', 'desc')
                ->get()
                ->map(fn ($p) => [
                    'id' => $p->id,
                    'name' => $p->person?->name_ar ?? $p->person?->name ?? '',
                ]);
        }

        return view('livewire.users.user-form', $viewData);
    }
}
