<?php

namespace App\Livewire\Programs;

use App\Domain\HR\Services\TrainerWorkloadService;
use App\Domain\Identity\Models\Branch;
use App\Domain\Pricing\Models\BasePrice;
use App\Domain\Training\Models\Activity;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Services\TrainingProgramService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Models\User;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('إدارة البرنامج')]
class ProgramForm extends Component
{
    public ?TrainingProgram $program = null;
    public bool $editing = false;

    public string $name = '';
    public string $name_ar = '';
    public string $slug = '';
    public ?int $activity_id = null;
    public ?int $branch_id = null;
    public ?int $default_trainer_id = null;
    public string $description = '';
    public string $description_ar = '';
    public string $skill_level = 'all';
    public ?int $age_min = null;
    public ?int $age_max = null;
    public string $gender = 'all';
    public int $sessions_per_week = 2;
    public int $session_duration_minutes = 60;
    public ?int $total_sessions = null;
    public ?int $program_duration_weeks = null;
    public int $min_participants = 1;
    public int $max_participants = 20;
    public bool $allow_waitlist = true;
    public ?int $attendance_requirement_percent = null;
    public bool $assessment_required = false;
    public bool $registration_open = true;
    public ?string $registration_deadline = null;
    public ?string $program_start_date = null;
    public ?string $program_end_date = null;
    public string $renewal_policy = 'manual_renew';
    public ?string $billing_cycle = 'monthly';
    public ?int $billing_day = 1;
    public string $cancellation_policy = '';
    public string $refund_policy = '';
    public string $status = 'active';
    public bool $featured = false;

    // Pricing
    public string $member_price = '';
    public string $non_member_price = '';

    /**
     * Product ids that come bundled with this programme. A player cannot be
     * considered properly enrolled without them, and the group view flags
     * anyone missing one.
     *
     * @var array<int>
     */
    public array $bundled_product_ids = [];

    public function mount(?TrainingProgram $program = null): void
    {
        if ($program && $program->exists) {
            $this->program = $program;
            $this->editing = true;
            $this->bundled_product_ids = $program->bundledProducts()->pluck('products.id')->all();
            $this->name = $program->name ?? '';
            $this->name_ar = $program->name_ar;
            $this->slug = $program->slug ?? '';
            $this->activity_id = $program->activity_id;
            $this->branch_id = $program->branch_id;
            $this->default_trainer_id = $program->default_trainer_id;
            $this->description = $program->description ?? '';
            $this->description_ar = $program->description_ar ?? '';
            $this->skill_level = $program->skill_level ?? 'all';
            $this->age_min = $program->age_min;
            $this->age_max = $program->age_max;
            $this->gender = $program->gender ?? 'all';
            $this->sessions_per_week = $program->sessions_per_week;
            $this->session_duration_minutes = $program->session_duration_minutes;
            $this->total_sessions = $program->total_sessions;
            $this->program_duration_weeks = $program->program_duration_weeks;
            $this->min_participants = $program->min_participants;
            $this->max_participants = $program->max_participants;
            $this->allow_waitlist = $program->allow_waitlist;
            $this->attendance_requirement_percent = $program->attendance_requirement_percent;
            $this->assessment_required = $program->assessment_required;
            $this->registration_open = $program->registration_open;
            $this->registration_deadline = $program->registration_deadline?->format('Y-m-d');
            $this->program_start_date = $program->program_start_date?->format('Y-m-d');
            $this->program_end_date = $program->program_end_date?->format('Y-m-d');
            $this->renewal_policy = $program->renewal_policy->value ?? $program->renewal_policy;
            $this->billing_cycle = $program->billing_cycle;
            $this->billing_day = $program->billing_day;
            $this->cancellation_policy = $program->cancellation_policy ?? '';
            $this->refund_policy = $program->refund_policy ?? '';
            $this->status = $program->status->value ?? $program->status;
            $this->featured = $program->featured;

            // Load existing prices
            $prices = BasePrice::where('priceable_type', TrainingProgram::class)
                ->where('priceable_id', $program->id)
                ->where('is_active', true)
                ->get();

            foreach ($prices as $price) {
                $meta = $price->metadata ?? [];
                if (($meta['membership_type'] ?? null) === 'member') {
                    $this->member_price = number_format($price->amount / 100, 2, '.', '');
                } elseif (($meta['membership_type'] ?? null) === 'non_member') {
                    $this->non_member_price = number_format($price->amount / 100, 2, '.', '');
                }
            }
        }
    }

    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'name_ar' => 'required|string|max:255',
            'slug' => 'nullable|string|max:100',
            'activity_id' => 'required|exists:activities,id',
            'branch_id' => 'nullable|exists:branches,id',
            'default_trainer_id' => 'nullable|exists:users,id',
            'description' => 'nullable|string',
            'description_ar' => 'nullable|string',
            'skill_level' => 'required|in:all,beginner,intermediate,advanced,professional',
            'age_min' => 'nullable|integer|min:1|max:99',
            'age_max' => 'nullable|integer|min:1|max:99',
            'gender' => 'required|in:all,male,female',
            'sessions_per_week' => 'required|integer|min:1|max:7',
            'session_duration_minutes' => 'required|integer|min:15|max:240',
            'total_sessions' => 'nullable|integer|min:1',
            'program_duration_weeks' => 'nullable|integer|min:1|max:104',
            'min_participants' => 'required|integer|min:1',
            'max_participants' => 'required|integer|min:1',
            'allow_waitlist' => 'boolean',
            'attendance_requirement_percent' => 'nullable|integer|min:0|max:100',
            'assessment_required' => 'boolean',
            'registration_open' => 'boolean',
            'registration_deadline' => 'nullable|date',
            'program_start_date' => 'nullable|date',
            'program_end_date' => 'nullable|date|after_or_equal:program_start_date',
            'renewal_policy' => 'required|in:auto_renew,manual_renew,one_time',
            'billing_cycle' => 'nullable|required_unless:renewal_policy,one_time|in:monthly,quarterly,semi_annual,annual,per_duration',
            'billing_day' => 'nullable|integer|min:1|max:28',
            'cancellation_policy' => 'nullable|string',
            'refund_policy' => 'nullable|string',
            'featured' => 'boolean',
            'member_price' => 'nullable|numeric|min:0',
            'non_member_price' => 'nullable|numeric|min:0',
        ];
    }

    public function messages(): array
    {
        return [
            'name.required' => 'اسم البرنامج بالإنجليزية مطلوب',
            'name.max' => 'اسم البرنامج بالإنجليزية يجب ألا يتجاوز 255 حرف',
            'name_ar.required' => 'اسم البرنامج بالعربية مطلوب',
            'name_ar.max' => 'اسم البرنامج بالعربية يجب ألا يتجاوز 255 حرف',
            'activity_id.required' => 'النشاط مطلوب',
            'activity_id.exists' => 'النشاط المحدد غير موجود',
            'branch_id.exists' => 'الفرع المحدد غير موجود',
            'skill_level.required' => 'مستوى المهارة مطلوب',
            'skill_level.in' => 'مستوى المهارة غير صالح',
            'age_min.min' => 'الحد الأدنى للعمر يجب أن يكون 1 على الأقل',
            'age_max.min' => 'الحد الأقصى للعمر يجب أن يكون 1 على الأقل',
            'gender.required' => 'الجنس مطلوب',
            'gender.in' => 'قيمة الجنس غير صالحة',
            'sessions_per_week.required' => 'عدد الحصص أسبوعياً مطلوب',
            'sessions_per_week.min' => 'عدد الحصص أسبوعياً يجب أن يكون 1 على الأقل',
            'sessions_per_week.max' => 'عدد الحصص أسبوعياً يجب ألا يتجاوز 7',
            'session_duration_minutes.required' => 'مدة الحصة مطلوبة',
            'session_duration_minutes.min' => 'مدة الحصة يجب أن تكون 15 دقيقة على الأقل',
            'session_duration_minutes.max' => 'مدة الحصة يجب ألا تتجاوز 240 دقيقة',
            'min_participants.required' => 'الحد الأدنى للمشتركين مطلوب',
            'min_participants.min' => 'الحد الأدنى للمشتركين يجب أن يكون 1 على الأقل',
            'max_participants.required' => 'الحد الأقصى للمشتركين مطلوب',
            'max_participants.min' => 'الحد الأقصى للمشتركين يجب أن يكون 1 على الأقل',
            'program_end_date.after_or_equal' => 'تاريخ انتهاء البرنامج يجب أن يكون بعد تاريخ البداية',
            'renewal_policy.required' => 'سياسة التجديد مطلوبة',
            'renewal_policy.in' => 'سياسة التجديد غير صالحة',
            'billing_cycle.required_unless' => 'دورة الفوترة مطلوبة عند تفعيل التجديد',
            'billing_cycle.in' => 'دورة الفوترة غير صالحة',
            'billing_day.integer' => 'يوم الفوترة يجب أن يكون رقم',
            'billing_day.min' => 'يوم الفوترة يجب أن يكون 1 على الأقل',
            'billing_day.max' => 'يوم الفوترة يجب ألا يتجاوز 28',
            'member_price.numeric' => 'سعر العضو يجب أن يكون رقم',
            'member_price.min' => 'سعر العضو يجب ألا يكون سالب',
            'non_member_price.numeric' => 'سعر غير العضو يجب أن يكون رقم',
            'non_member_price.min' => 'سعر غير العضو يجب ألا يكون سالب',
        ];
    }

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

        try {
            $data = [
                'name' => $this->name,
                'name_ar' => $this->name_ar,
                'slug' => $this->slug ?: null,
                'activity_id' => $this->activity_id,
                'branch_id' => $this->branch_id,
                'default_trainer_id' => $this->default_trainer_id,
                'status' => $this->status,
                'description' => $this->description ?: null,
                'description_ar' => $this->description_ar ?: null,
                'skill_level' => $this->skill_level,
                'age_min' => $this->age_min,
                'age_max' => $this->age_max,
                'gender' => $this->gender,
                'sessions_per_week' => $this->sessions_per_week,
                'session_duration_minutes' => $this->session_duration_minutes,
                'total_sessions' => $this->total_sessions,
                'program_duration_weeks' => $this->program_duration_weeks,
                'min_participants' => $this->min_participants,
                'max_participants' => $this->max_participants,
                'allow_waitlist' => $this->allow_waitlist,
                'attendance_requirement_percent' => $this->attendance_requirement_percent,
                'assessment_required' => $this->assessment_required,
                'registration_open' => $this->registration_open,
                'registration_deadline' => $this->registration_deadline ?: null,
                'program_start_date' => $this->program_start_date ?: null,
                'program_end_date' => $this->program_end_date ?: null,
                'renewal_policy' => $this->renewal_policy,
                'billing_cycle' => $this->renewal_policy !== 'one_time' ? $this->billing_cycle : null,
                'billing_day' => $this->billing_cycle === 'monthly' ? $this->billing_day : null,
                'cancellation_policy' => $this->cancellation_policy ?: null,
                'refund_policy' => $this->refund_policy ?: null,
                'featured' => $this->featured,
            ];

            if ($this->editing) {
                $service->update($this->program, $data);
                $this->savePrices($this->program);
                $this->saveBundledProducts($this->program);
                session()->flash('success', __('تم تحديث البرنامج بنجاح'));
            } else {
                $program = $service->create($data, auth()->user());
                $this->savePrices($program);
                $this->saveBundledProducts($program);
                session()->flash('success', __('تم إنشاء البرنامج بنجاح'));
            }

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

    /**
     * Sync the bundle. academy_id is written explicitly because the pivot has
     * no model and so no BelongsToAcademy hook to stamp it.
     */
    private function saveBundledProducts(TrainingProgram $program): void
    {
        $academyId = $program->academy_id ?? app('current_academy')?->id;

        $payload = [];
        foreach (array_filter($this->bundled_product_ids) as $productId) {
            $payload[(int) $productId] = [
                'academy_id' => $academyId,
                'is_required' => true,
                'quantity' => 1,
            ];
        }

        $program->bundledProducts()->sync($payload);
    }

    private function savePrices(TrainingProgram $program): void
    {
        $types = [
            'member' => $this->member_price,
            'non_member' => $this->non_member_price,
        ];

        foreach ($types as $membershipType => $priceDisplay) {
            $amount = $priceDisplay ? (int) round((float) $priceDisplay * 100) : null;

            $existing = BasePrice::where('priceable_type', TrainingProgram::class)
                ->where('priceable_id', $program->id)
                ->where('metadata->membership_type', $membershipType)
                ->first();

            if ($amount && $amount > 0) {
                if ($existing) {
                    $existing->update(['amount' => $amount, 'is_active' => true]);
                } else {
                    BasePrice::create([
                        'academy_id' => $program->academy_id,
                        'priceable_type' => TrainingProgram::class,
                        'priceable_id' => $program->id,
                        'branch_id' => $program->branch_id,
                        'name_ar' => $membershipType === 'member' ? 'سعر العضو' : 'سعر غير العضو',
                        'name' => $membershipType === 'member' ? 'Member Price' : 'Non-Member Price',
                        'amount' => $amount,
                        'currency' => 'EGP',
                        'effective_from' => now()->toDateString(),
                        'is_active' => true,
                        'priority' => $membershipType === 'member' ? 1 : 2,
                        'created_by' => auth()->id(),
                        'metadata' => ['membership_type' => $membershipType],
                    ]);
                }
            } elseif ($existing) {
                $existing->update(['is_active' => false]);
            }
        }
    }

    public function render()
    {
        $trainers = User::whereHas('roles', fn ($q) => $q->whereIn('slug', ['trainer', 'head_trainer']))
            ->where('status', 'active')
            ->orderBy('name')
            ->get(['id', 'name', 'name_ar']);

        $workloads = app(TrainerWorkloadService::class)->getWorkloadsForUsers($trainers->pluck('id')->toArray());

        return view('livewire.programs.program-form', [
            'availableProducts' => \App\Domain\Inventory\Models\Product::where('is_active', true)
                ->orderBy('name_ar')->get(['id', 'name_ar', 'selling_price']),
            'activities' => Activity::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
            'branches' => Branch::orderBy('name_ar')->get(['id', 'name_ar']),
            'trainers' => $trainers,
            'trainerWorkloads' => $workloads,
        ]);
    }
}
