<?php

namespace App\Livewire\Enrollments;

use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Services\InvoiceService;
use App\Domain\Participant\Models\Participant;
use App\Domain\Pricing\Services\PricingService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Services\EnrollmentService;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('نقل مشترك')]
class TransferParticipantWizard extends Component
{
    public int $currentStep = 1;
    public int $totalSteps = 4;
    public bool $completed = false;

    // Step 1: Select Participant & Enrollment
    public string $participantSearch = '';
    public ?int $participantId = null;
    public ?int $enrollmentId = null;

    // Step 2: Destination
    public ?int $destinationProgramId = null;
    public ?int $destinationGroupId = null;

    // Step 3: Impact & Reason
    public string $reason = '';

    // Price difference
    public int $sourceProgramPrice = 0;
    public int $destinationProgramPrice = 0;
    public int $priceDifference = 0;
    public bool $requiresPayment = false;

    // Cached data for display
    public ?array $selectedParticipant = null;
    public array $activeEnrollments = [];
    public ?array $selectedEnrollment = null;
    public ?array $sourceGroup = null;
    public ?array $destinationGroup = null;
    public ?string $createdInvoiceUuid = null;

    public function mount(): void
    {
        $this->authorize('enrollments.transfer');
    }

    public function getStepLabels(): array
    {
        return [
            1 => 'اختيار المشترك',
            2 => 'الوجهة',
            3 => 'التأثير',
            4 => 'تأكيد النقل',
        ];
    }

    public function selectParticipant(int $id): void
    {
        $participant = Participant::with('person')->findOrFail($id);
        $this->participantId = $id;
        $this->selectedParticipant = [
            'id' => $participant->id,
            'name' => $participant->person?->name_ar ?? $participant->person?->name ?? '-',
            'participant_number' => $participant->participant_number,
        ];

        $this->loadActiveEnrollments();
    }

    public function updatedParticipantId(): void
    {
        if ($this->participantId) {
            $this->loadActiveEnrollments();
        } else {
            $this->activeEnrollments = [];
        }
        $this->enrollmentId = null;
        $this->selectedEnrollment = null;
        $this->sourceGroup = null;
    }

    private function loadActiveEnrollments(): void
    {
        $enrollments = Enrollment::where('participant_id', $this->participantId)
            ->where('status', 'active')
            ->with(['group', 'program'])
            ->get();

        $this->activeEnrollments = $enrollments->map(fn ($e) => [
            'id' => $e->id,
            'group_name' => $e->group?->name_ar ?? '-',
            'program_name' => $e->program?->name_ar ?? '-',
            'enrollment_date' => $e->enrollment_date?->format('Y-m-d'),
            'group_id' => $e->training_group_id,
            'program_id' => $e->training_program_id,
        ])->toArray();
    }

    public function selectEnrollment(int $id): void
    {
        $enrollment = Enrollment::with(['group', 'program'])->findOrFail($id);
        $this->enrollmentId = $id;
        $this->selectedEnrollment = [
            'id' => $enrollment->id,
            'group_name' => $enrollment->group?->name_ar ?? '-',
            'program_name' => $enrollment->program?->name_ar ?? '-',
            'group_id' => $enrollment->training_group_id,
            'program_id' => $enrollment->training_program_id,
        ];
        $this->sourceGroup = [
            'id' => $enrollment->group?->id,
            'name_ar' => $enrollment->group?->name_ar,
            'current_count' => $enrollment->group?->current_count,
            'max_capacity' => $enrollment->group?->max_capacity,
        ];
    }

    public function selectDestinationProgram(?int $id): void
    {
        $this->destinationProgramId = $id;
        $this->destinationGroupId = null;
        $this->destinationGroup = null;
        $this->priceDifference = 0;
        $this->requiresPayment = false;
    }

    public function selectDestinationGroup(int $id): void
    {
        $group = TrainingGroup::with('program')->findOrFail($id);
        $this->destinationGroupId = $id;
        $this->destinationGroup = [
            'id' => $group->id,
            'name_ar' => $group->name_ar,
            'program_name' => $group->program?->name_ar ?? '-',
            'current_count' => $group->current_count,
            'max_capacity' => $group->max_capacity,
        ];

        $this->calculatePriceDifference($group);
    }

    private function calculatePriceDifference(TrainingGroup $destGroup): void
    {
        $this->priceDifference = 0;
        $this->requiresPayment = false;

        if (!$this->selectedEnrollment || !$this->participantId) {
            return;
        }

        $participant = Participant::find($this->participantId);
        $sourceProgram = TrainingProgram::find($this->selectedEnrollment['program_id']);
        $destProgram = $destGroup->program;

        if (!$sourceProgram || !$destProgram || !$participant) {
            return;
        }

        $pricingService = app(PricingService::class);

        try {
            $sourceResult = $pricingService->calculate($sourceProgram, $participant);
            $this->sourceProgramPrice = $sourceResult->finalAmount;
        } catch (DomainException) {
            $this->sourceProgramPrice = 0;
        }

        try {
            $destResult = $pricingService->calculate($destProgram, $participant);
            $this->destinationProgramPrice = $destResult->finalAmount;
        } catch (DomainException) {
            $this->destinationProgramPrice = 0;
        }

        $diff = $this->destinationProgramPrice - $this->sourceProgramPrice;
        if ($diff > 0) {
            $this->priceDifference = $diff;
            $this->requiresPayment = true;
        }
    }

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

        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 confirm(): void
    {
        try {
            $enrollment = Enrollment::findOrFail($this->enrollmentId);
            $toGroup = TrainingGroup::findOrFail($this->destinationGroupId);

            $newEnrollment = app(EnrollmentService::class)->transfer($enrollment, $toGroup, auth()->user());

            // Create price difference invoice if destination is more expensive
            if ($this->requiresPayment && $this->priceDifference > 0) {
                $invoice = app(InvoiceService::class)->create([
                    'billable_type' => Participant::class,
                    'billable_id' => $this->participantId,
                    'branch_id' => $toGroup->branch_id ?? auth()->user()->branch_id,
                    'due_date' => now()->addDays(7)->toDateString(),
                    'notes' => 'فاتورة فرق سعر نقل — اشتراك #' . $newEnrollment->id,
                ], [[
                    'description' => 'فرق سعر نقل من ' . ($this->selectedEnrollment['program_name'] ?? '-') . ' إلى ' . ($this->destinationGroup['program_name'] ?? '-'),
                    'quantity' => 1,
                    'unit_price' => $this->priceDifference,
                ]], auth()->user());

                $this->createdInvoiceUuid = $invoice->uuid;
            }

            $this->completed = true;
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    private function rulesForStep(int $step): array
    {
        return match ($step) {
            1 => [
                'participantId' => 'required|integer|exists:participants,id',
                'enrollmentId' => 'required|integer|exists:enrollments,id',
            ],
            2 => [
                'destinationGroupId' => 'required|integer|exists:training_groups,id',
            ],
            3 => [
                'reason' => 'required|string|min:5|max:500',
            ],
            default => [],
        };
    }

    public function render()
    {
        $searchResults = collect();
        if (strlen($this->participantSearch) >= 2) {
            $searchResults = Participant::with('person')
                ->whereHas('person', function ($q) {
                    $q->where('name_ar', 'ilike', "%{$this->participantSearch}%")
                      ->orWhere('name', 'ilike', "%{$this->participantSearch}%")
                      ->orWhere('phone', 'ilike', "%{$this->participantSearch}%")
                      ->orWhere('national_id', 'ilike', "%{$this->participantSearch}%");
                })
                ->orWhere('participant_number', 'ilike', "%{$this->participantSearch}%")
                ->where('status', 'active')
                ->limit(10)
                ->get();
        }

        $availablePrograms = collect();
        $availableGroups = collect();
        if ($this->selectedEnrollment && $this->currentStep >= 2) {
            $availablePrograms = TrainingProgram::where('status', 'active')
                ->orderBy('name_ar')
                ->get();

            $targetProgramId = $this->destinationProgramId ?? $this->selectedEnrollment['program_id'];

            $availableGroups = TrainingGroup::where('training_program_id', $targetProgramId)
                ->where('id', '!=', $this->selectedEnrollment['group_id'])
                ->whereIn('status', ['forming', 'active'])
                ->with('program')
                ->orderBy('name_ar')
                ->get();
        }

        return view('livewire.enrollments.transfer-participant-wizard', [
            'searchResults' => $searchResults,
            'availablePrograms' => $availablePrograms,
            'availableGroups' => $availableGroups,
        ]);
    }
}
