<?php

namespace App\Livewire\Facilities;

use App\Domain\Facility\Services\FacilityService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('إنشاء منشأة جديدة')]
class CreateFacilityWizard extends Component
{
    use UsesBranchScope;

    public int $currentStep = 1;
    public int $totalSteps = 4;
    public bool $completed = false;

    // Step 1: Basic Info
    public string $nameAr = '';
    public string $name = '';
    public string $type = '';
    public ?int $branchId = null;
    public ?int $capacity = null;
    public string $descriptionAr = '';

    // Step 2: Specs
    public string $surfaceType = '';
    public ?string $areaSqm = null;
    public ?string $lengthM = null;
    public ?string $widthM = null;
    public bool $isIndoor = false;
    public bool $hasLighting = false;
    public bool $hasAc = false;

    // Step 3: Operating Hours
    public string $operatingStart = '';
    public string $operatingEnd = '';
    public string $rentalCostPerHour = '';
    public string $address = '';

    // Data. Server-built and only iterated in the view, so it is locked: the
    // browser must not be able to add a branch to its own picker. The
    // validation rule recomputes the allowed ids from selectableBranches()
    // rather than trusting this array either way.
    #[Locked]
    public array $branches = [];

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

        // Only the branches this user may actually file a record under — one
        // entry unless they are genuinely in all-branches mode. Offering every
        // branch here let a user in branch A create a facility that landed in
        // branch B and then vanished from their own screens.
        $this->branches = $this->selectableBranches()
            ->map(fn ($branch) => ['id' => (int) $branch->id, 'name_ar' => $branch->name_ar])
            ->values()
            ->all();

        if (count($this->branches) === 1) {
            $this->branchId = $this->branches[0]['id'];
        }
    }

    /**
     * The branch ids this wizard may write. Recomputed rather than read off the
     * $branches array, which is a public property and therefore settable from
     * the browser.
     */
    private function selectableBranchIds(): array
    {
        return $this->selectableBranches()->pluck('id')->map(fn ($id) => (int) $id)->all();
    }

    /** Sports this facility can host (empty = any). */
    public array $activityIds = [];

    /** Starting grid. 1x1 means "one whole space, not subdivided yet". */
    public int $gridRows = 1;
    public int $gridColumns = 1;

    public function getStepLabels(): array
    {
        return [
            1 => 'المعلومات الأساسية',
            2 => 'المواصفات',
            3 => 'ساعات التشغيل',
            4 => 'مراجعة',
        ];
    }

    public function rulesForStep(): array
    {
        return match ($this->currentStep) {
            1 => [
                'nameAr' => 'required|string|max:255',
                'name' => 'nullable|string|max:255',
                'type' => 'required|in:field,court,pool,gym,track,hall,room,outdoor,other',
                // exists: is a raw table query — it would accept any branch in
                // the academy. The branch must be one this user may write to.
                'branchId' => ['required', Rule::in($this->selectableBranchIds())],
                'capacity' => 'nullable|integer|min:1',
                'descriptionAr' => 'nullable|string|max:1000',
            ],
            2 => [
                'surfaceType' => 'nullable|string|max:100',
                'areaSqm' => 'nullable|numeric|min:0',
                'lengthM' => 'nullable|numeric|min:0',
                'widthM' => 'nullable|numeric|min:0',
                'isIndoor' => 'boolean',
                'hasLighting' => 'boolean',
                'hasAc' => 'boolean',
            ],
            3 => [
                'operatingStart' => 'nullable|date_format:H:i',
                'operatingEnd' => 'nullable|date_format:H:i|after:operatingStart',
                'rentalCostPerHour' => 'nullable|numeric|min:0',
                'address' => 'nullable|string|max:500',
            ],
            default => [],
        };
    }

    public function messages(): array
    {
        return [
            'nameAr.required' => 'اسم المنشأة بالعربية مطلوب',
            'type.required' => 'نوع المنشأة مطلوب',
            'type.in' => 'نوع المنشأة غير صالح',
            'branchId.required' => 'الفرع مطلوب',
            'branchId.in' => 'الفرع المختار غير متاح',
            'capacity.integer' => 'السعة يجب أن تكون رقمًا صحيحًا',
            'capacity.min' => 'السعة يجب أن تكون 1 على الأقل',
            'areaSqm.numeric' => 'المساحة يجب أن تكون رقمًا',
            'lengthM.numeric' => 'الطول يجب أن يكون رقمًا',
            'widthM.numeric' => 'العرض يجب أن يكون رقمًا',
            'operatingEnd.after' => 'وقت الإغلاق يجب أن يكون بعد وقت الافتتاح',
            'rentalCostPerHour.numeric' => 'تكلفة الإيجار يجب أن تكون رقمًا',
        ];
    }

    public function nextStep(): void
    {
        $this->validate($this->rulesForStep(), $this->messages());
        $this->currentStep = min($this->currentStep + 1, $this->totalSteps);
    }

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

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

    public function confirm(): void
    {
        // Re-validated here, not only when step 1 was left. branchId is a plain
        // public property, so the browser can re-set it on any round-trip
        // between the two — validating in nextStep() and writing in confirm()
        // is the same shape as validating in mount() and querying in render().
        $this->validate(
            ['branchId' => ['required', Rule::in($this->selectableBranchIds())]],
            [
                'branchId.required' => 'الفرع مطلوب',
                'branchId.in' => 'الفرع المختار غير متاح',
            ],
        );

        try {
            $data = [
                'name_ar' => $this->nameAr,
                'name' => $this->name ?: null,
                'type' => $this->type,
                'branch_id' => $this->branchId,
                'capacity' => $this->capacity,
                'description_ar' => $this->descriptionAr ?: null,
                'surface_type' => $this->surfaceType ?: null,
                'area_sqm' => $this->areaSqm ? (float) $this->areaSqm : null,
                'length_m' => $this->lengthM ? (float) $this->lengthM : null,
                'width_m' => $this->widthM ? (float) $this->widthM : null,
                'is_indoor' => $this->isIndoor,
                'has_lighting' => $this->hasLighting,
                'has_ac' => $this->hasAc,
                'operating_start' => $this->operatingStart ?: null,
                'operating_end' => $this->operatingEnd ?: null,
                'rental_cost_per_hour' => $this->rentalCostPerHour ? (int) round((float) $this->rentalCostPerHour * 100) : null,
                'address' => $this->address ?: null,
                'status' => 'active',
            ];

            app(FacilityService::class)->create(
                $data,
                auth()->user(),
                $this->activityIds,
                ['rows' => $this->gridRows, 'columns' => $this->gridColumns],
            );

            $this->completed = true;
            session()->flash('success', 'تم إنشاء المنشأة بنجاح');
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function render()
    {
        return view('livewire.facilities.create-facility-wizard', [
            'activities' => \App\Domain\Training\Models\Activity::where('is_active', true)
                ->orderBy('name_ar')
                ->get(['id', 'name_ar']),
        ]);
    }
}
