<?php

namespace App\Livewire\Programs;

use App\Domain\Facility\Models\Facility;
use App\Domain\Identity\Models\Branch;
use App\Domain\Pricing\Models\BasePrice;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Models\Activity;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Models\TrainingSchedule;
use App\Domain\Training\Services\TrainingProgramService;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('إنشاء برنامج تدريبي')]
class CreateProgramWizard extends Component
{
    public int $currentStep = 1;
    public int $totalSteps = 7;
    public bool $completed = false;

    // Step 1: Basic Info
    public string $nameAr = '';
    public string $name = '';
    public ?int $activityId = null;
    public ?int $branchId = null;
    public string $skillLevel = '';
    public string $ageMin = '';
    public string $ageMax = '';
    public string $gender = '';
    public string $descriptionAr = '';
    public string $minParticipants = '5';
    public string $maxParticipants = '20';
    public string $programDurationWeeks = '12';
    public string $sessionDurationMinutes = '60';

    // Step 2: Head Trainer
    public ?int $headTrainerId = null;
    public bool $skipTrainer = false;

    // Step 3: Schedule Template
    public array $scheduleRows = [];

    // Step 4: Initial Group
    public bool $createInitialGroup = true;
    public string $groupName = '';
    public string $groupCode = '';
    public string $groupCapacity = '';

    // Step 5: Pricing
    public string $basePrice = '';

    // Step 6: Facility
    public bool $assignFacility = false;
    public ?int $facilityId = null;

    public function mount(): void
    {
        $this->authorize('programs.create');
        $this->addScheduleRow();
    }

    public function getStepLabels(): array
    {
        return [
            1 => 'المعلومات الأساسية',
            2 => 'المدرب الرئيسي',
            3 => 'جدول التدريب',
            4 => 'المجموعة الأولى',
            5 => 'التسعير',
            6 => 'المنشأة',
            7 => 'مراجعة وتأكيد',
        ];
    }

    public function addScheduleRow(): void
    {
        $this->scheduleRows[] = [
            'day_of_week' => '0',
            'start_time' => '16:00',
            'end_time' => '17:00',
        ];
    }

    public function removeScheduleRow(int $index): void
    {
        if (count($this->scheduleRows) > 1) {
            unset($this->scheduleRows[$index]);
            $this->scheduleRows = array_values($this->scheduleRows);
        }
    }

    public function updatedBranchId(): void
    {
        // Reset facility when branch changes
        $this->facilityId = null;
    }

    public function updatedCreateInitialGroup(): void
    {
        if ($this->createInitialGroup && empty($this->groupName)) {
            $this->generateGroupDefaults();
        }
    }

    private function generateGroupDefaults(): void
    {
        $programName = $this->nameAr ?: 'برنامج';
        $this->groupName = "{$programName} - مجموعة 1";
        $this->groupCode = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', $this->name ?: Str::random(4)), 0, 6)) . '01';
        $this->groupCapacity = $this->maxParticipants ?: '20';
    }

    public function rulesForStep(int $step): array
    {
        return match ($step) {
            1 => [
                'nameAr' => 'required|string|max:255',
                'name' => 'nullable|string|max:255',
                'activityId' => 'required|exists:activities,id',
                'branchId' => 'required|exists:branches,id',
                'skillLevel' => 'nullable|in:all,beginner,intermediate,advanced,professional',
                'ageMin' => 'nullable|integer|min:2|max:99',
                'ageMax' => 'nullable|integer|min:2|max:99|gte:ageMin',
                'gender' => 'nullable|in:all,male,female',
                'minParticipants' => 'required|integer|min:1',
                'maxParticipants' => 'required|integer|min:1|gte:minParticipants',
                'programDurationWeeks' => 'required|integer|min:1|max:104',
                'sessionDurationMinutes' => 'required|integer|min:15|max:300',
            ],
            2 => [
                'headTrainerId' => $this->skipTrainer ? 'nullable' : 'required|exists:users,id',
            ],
            3 => [
                'scheduleRows' => 'required|array|min:1',
                'scheduleRows.*.day_of_week' => 'required|integer|min:0|max:6',
                'scheduleRows.*.start_time' => 'required|date_format:H:i',
                'scheduleRows.*.end_time' => 'required|date_format:H:i|after:scheduleRows.*.start_time',
            ],
            4 => [
                'createInitialGroup' => 'boolean',
                'groupName' => $this->createInitialGroup ? 'required|string|max:255' : 'nullable',
                'groupCode' => $this->createInitialGroup ? 'required|string|max:10' : 'nullable',
                'groupCapacity' => $this->createInitialGroup ? 'required|integer|min:1' : 'nullable',
            ],
            5 => [
                'basePrice' => 'required|numeric|min:0',
            ],
            6 => [
                'facilityId' => $this->assignFacility ? 'required|exists:facilities,id' : 'nullable',
            ],
            default => [],
        };
    }

    public function messagesForStep(int $step): array
    {
        return match ($step) {
            1 => [
                'nameAr.required' => 'اسم البرنامج بالعربي مطلوب',
                'activityId.required' => 'يجب اختيار النشاط',
                'activityId.exists' => 'النشاط المختار غير موجود',
                'branchId.required' => 'يجب اختيار الفرع',
                'branchId.exists' => 'الفرع غير موجود',
                'ageMin.integer' => 'الحد الأدنى للعمر يجب أن يكون رقم صحيح',
                'ageMax.gte' => 'الحد الأقصى للعمر يجب أن يكون أكبر من أو يساوي الحد الأدنى',
                'gender.in' => 'قيمة الجنس غير صالحة',
                'minParticipants.required' => 'الحد الأدنى للمشتركين مطلوب',
                'maxParticipants.required' => 'الحد الأقصى للمشتركين مطلوب',
                'maxParticipants.gte' => 'الحد الأقصى يجب أن يكون أكبر من أو يساوي الحد الأدنى',
                'programDurationWeeks.required' => 'مدة البرنامج مطلوبة',
                'sessionDurationMinutes.required' => 'مدة الحصة مطلوبة',
            ],
            2 => [
                'headTrainerId.required' => 'يجب اختيار المدرب الرئيسي أو تخطي هذه الخطوة',
                'headTrainerId.exists' => 'المدرب المختار غير موجود',
            ],
            3 => [
                'scheduleRows.required' => 'يجب إضافة يوم تدريب واحد على الأقل',
                'scheduleRows.min' => 'يجب إضافة يوم تدريب واحد على الأقل',
                'scheduleRows.*.day_of_week.required' => 'يجب اختيار اليوم',
                'scheduleRows.*.start_time.required' => 'وقت البدء مطلوب',
                'scheduleRows.*.end_time.required' => 'وقت الانتهاء مطلوب',
                'scheduleRows.*.end_time.after' => 'وقت الانتهاء يجب أن يكون بعد وقت البدء',
            ],
            4 => [
                'groupName.required' => 'اسم المجموعة مطلوب',
                'groupCode.required' => 'كود المجموعة مطلوب',
                'groupCapacity.required' => 'سعة المجموعة مطلوبة',
                'groupCapacity.integer' => 'السعة يجب أن تكون رقم صحيح',
            ],
            5 => [
                'basePrice.required' => 'السعر الأساسي مطلوب',
                'basePrice.numeric' => 'السعر يجب أن يكون رقم',
                'basePrice.min' => 'السعر لا يمكن أن يكون سالب',
            ],
            6 => [
                'facilityId.required' => 'يجب اختيار المنشأة',
                'facilityId.exists' => 'المنشأة المختارة غير موجودة',
            ],
            default => [],
        };
    }

    public function nextStep(): void
    {
        $this->validate(
            $this->rulesForStep($this->currentStep),
            $this->messagesForStep($this->currentStep)
        );

        // Auto-generate group defaults when moving past step 1
        if ($this->currentStep === 1 && $this->createInitialGroup && empty($this->groupName)) {
            $this->generateGroupDefaults();
        }

        if ($this->currentStep < $this->totalSteps) {
            $this->currentStep++;
        }
    }

    public function previousStep(): void
    {
        if ($this->currentStep > 1) {
            $this->currentStep--;
        }
    }

    public function goToStep(int $step): void
    {
        if ($step < $this->currentStep) {
            $this->currentStep = $step;
        }
    }

    public function toggleSkipTrainer(): void
    {
        $this->skipTrainer = !$this->skipTrainer;
        if ($this->skipTrainer) {
            $this->headTrainerId = null;
        }
    }

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

                // 1. Create Training Program
                $programData = [
                    'academy_id' => $academyId,
                    'name_ar' => $this->nameAr,
                    'name' => $this->name ?: $this->nameAr,
                    'activity_id' => $this->activityId,
                    'branch_id' => $this->branchId,
                    'default_trainer_id' => $this->headTrainerId,
                    'skill_level' => $this->skillLevel ?: 'all',
                    'age_min' => $this->ageMin ?: null,
                    'age_max' => $this->ageMax ?: null,
                    'gender' => $this->gender ?: 'all',
                    'description_ar' => $this->descriptionAr ?: null,
                    'sessions_per_week' => count($this->scheduleRows),
                    'session_duration_minutes' => (int) $this->sessionDurationMinutes,
                    'program_duration_weeks' => (int) $this->programDurationWeeks,
                    'min_participants' => (int) $this->minParticipants,
                    'max_participants' => (int) $this->maxParticipants,
                    'status' => 'active',
                ];

                $program = app(TrainingProgramService::class)->create($programData, $actor, skipDefaultGroup: true);

                // 2. Create Initial Group (if enabled)
                $group = null;
                if ($this->createInitialGroup) {
                    // Ensure unique code
                    $code = $this->groupCode;
                    $attempt = 0;
                    while (TrainingGroup::withTrashed()->where('academy_id', $academyId)->where('code', $code)->exists()) {
                        $attempt++;
                        $code = $this->groupCode . $attempt;
                    }

                    $group = TrainingGroup::create([
                        'academy_id' => $academyId,
                        'training_program_id' => $program->id,
                        'branch_id' => $this->branchId,
                        'name' => $this->groupName,
                        'name_ar' => $this->groupName,
                        'code' => $code,
                        'head_trainer_id' => $this->headTrainerId,
                        'max_capacity' => (int) $this->groupCapacity,
                        'current_count' => 0,
                        'waitlist_count' => 0,
                        'status' => 'forming',
                        'status_changed_at' => now(),
                        'start_date' => now()->toDateString(),
                        'created_by' => $actor->id,
                    ]);
                }

                // 3. Create Schedule Records (linked to the group if created)
                if ($group) {
                    foreach ($this->scheduleRows as $row) {
                        TrainingSchedule::create([
                            'academy_id' => $academyId,
                            'training_group_id' => $group->id,
                            'facility_id' => $this->assignFacility ? $this->facilityId : null,
                            'day_of_week' => (int) $row['day_of_week'],
                            'start_time' => $row['start_time'],
                            'end_time' => $row['end_time'],
                            'trainer_id' => $this->headTrainerId,
                            'effective_from' => now()->toDateString(),
                            'is_active' => true,
                        ]);
                    }
                }

                // 4. Create BasePrice record
                $amountPiasters = (int) round((float) $this->basePrice * 100);
                BasePrice::create([
                    'academy_id' => $academyId,
                    'priceable_type' => TrainingProgram::class,
                    'priceable_id' => $program->id,
                    'branch_id' => $this->branchId,
                    'name_ar' => "اشتراك {$this->nameAr}",
                    'name' => "Subscription {$this->name}",
                    'amount' => $amountPiasters,
                    'currency' => 'EGP',
                    'effective_from' => now()->toDateString(),
                    'is_active' => true,
                    'priority' => 0,
                    'created_by' => $actor->id,
                ]);
            });

            $this->completed = true;
            session()->flash('success', 'تم إنشاء البرنامج التدريبي بنجاح مع كل الإعدادات المطلوبة');
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        } catch (\Exception $e) {
            session()->flash('error', 'حدث خطأ غير متوقع: ' . $e->getMessage());
        }
    }

    public function render()
    {
        $trainers = collect();
        if ($this->currentStep === 2 || $this->currentStep === 7) {
            $trainerRoleSlugs = ['trainer', 'head_trainer'];
            $trainers = User::where('status', 'active')
                ->whereHas('roles', function ($q) use ($trainerRoleSlugs) {
                    $q->whereIn('slug', $trainerRoleSlugs);
                })
                ->orderBy('name_ar')
                ->get(['id', 'name', 'name_ar']);
        }

        $facilities = collect();
        if (($this->currentStep === 6 || $this->currentStep === 7) && $this->branchId) {
            $facilities = Facility::where('status', 'active')
                ->where('branch_id', $this->branchId)
                ->orderBy('name_ar')
                ->get(['id', 'name_ar', 'name', 'type']);
        }

        return view('livewire.programs.create-program-wizard', [
            'stepLabels' => $this->getStepLabels(),
            'activities' => Activity::orderBy('name_ar')->get(['id', 'name_ar', 'name']),
            'branches' => Branch::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
            'trainers' => $trainers,
            'facilities' => $facilities,
        ]);
    }
}
