<?php

namespace App\Livewire\Evaluations;

use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\Evaluation;
use App\Domain\Training\Models\EvaluationCriterion;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Services\EvaluationService;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('تقييم جديد')]
class EvaluationForm extends Component
{
    use UsesBranchScope;

    public ?Evaluation $evaluation = null;

    public string $participant_id = '';
    public string $training_group_id = '';
    public string $evaluation_date = '';
    public string $period_from = '';
    public string $period_to = '';
    public string $overall_notes = '';
    public array $scores = [];

    public function mount(?Evaluation $evaluation = null): void
    {
        if ($evaluation && $evaluation->exists) {
            $this->authorize('evaluations.update');
            $this->evaluation = $evaluation;
            $this->participant_id = (string) $evaluation->participant_id;
            $this->training_group_id = (string) $evaluation->training_group_id;
            $this->evaluation_date = $evaluation->evaluation_date->format('Y-m-d');
            $this->period_from = $evaluation->period_from?->format('Y-m-d') ?? '';
            $this->period_to = $evaluation->period_to?->format('Y-m-d') ?? '';
            $this->overall_notes = $evaluation->overall_notes ?? '';

            foreach ($evaluation->scores as $score) {
                $this->scores[$score->criterion_id] = [
                    'score' => (string) $score->score,
                    'notes' => $score->notes ?? '',
                ];
            }
        } else {
            $this->authorize('evaluations.create');
            $this->evaluation_date = now()->format('Y-m-d');
        }

        $this->initializeScores();
    }

    private function initializeScores(): void
    {
        $criteria = EvaluationCriterion::active()->orderBy('sort_order')->get();
        foreach ($criteria as $criterion) {
            if (!isset($this->scores[$criterion->id])) {
                $this->scores[$criterion->id] = [
                    'score' => '',
                    'notes' => '',
                ];
            }
        }
    }

    public function rules(): array
    {
        // `exists:` is a raw table query: it never sees the branch global
        // scope, and both ids are plain public properties the browser can set.
        // Without the branch clause the rule happily validates another
        // branch's player into another branch's group, and saveEvaluation()
        // writes the ids straight through without a scoped model lookup.
        // Null only in all-branches mode, where there is nothing to narrow to.
        $branchId = $this->getActiveBranchId();
        $inBranch = fn (string $table) => $branchId === null
            ? Rule::exists($table, 'id')
            : Rule::exists($table, 'id')->where('branch_id', $branchId);

        return [
            'participant_id' => ['required', $inBranch('participants')],
            'training_group_id' => ['required', $inBranch('training_groups')],
            'evaluation_date' => 'required|date',
            'period_from' => 'nullable|date',
            'period_to' => 'nullable|date|after_or_equal:period_from',
            'overall_notes' => 'nullable|string|max:2000',
            'scores.*.score' => 'nullable|numeric|min:0',
            'scores.*.notes' => 'nullable|string|max:500',
        ];
    }

    public function messages(): array
    {
        return [
            'participant_id.required' => __('يجب اختيار المشترك'),
            'participant_id.exists' => __('المشترك غير موجود'),
            'training_group_id.required' => __('يجب اختيار المجموعة'),
            'training_group_id.exists' => __('المجموعة غير موجودة'),
            'evaluation_date.required' => __('يجب تحديد تاريخ التقييم'),
            'evaluation_date.date' => __('تاريخ التقييم غير صحيح'),
            'period_to.after_or_equal' => __('تاريخ النهاية يجب أن يكون بعد تاريخ البداية'),
            'scores.*.score.numeric' => __('الدرجة يجب أن تكون رقماً'),
            'scores.*.score.min' => __('الدرجة لا يمكن أن تكون سالبة'),
        ];
    }

    public function saveDraft(EvaluationService $service): void
    {
        $this->validate();
        $this->saveEvaluation($service, false);
    }

    public function submit(EvaluationService $service): void
    {
        $this->validate();
        $this->saveEvaluation($service, true);
    }

    private function saveEvaluation(EvaluationService $service, bool $shouldSubmit): void
    {
        try {
            $data = [
                'academy_id' => app('current_academy')->id,
                'participant_id' => $this->participant_id,
                'training_group_id' => $this->training_group_id,
                'evaluation_date' => $this->evaluation_date,
                'period_from' => $this->period_from ?: null,
                'period_to' => $this->period_to ?: null,
                'overall_notes' => $this->overall_notes ?: null,
            ];

            $scoreData = [];
            foreach ($this->scores as $criterionId => $scoreInfo) {
                if ($scoreInfo['score'] !== '' && $scoreInfo['score'] !== null) {
                    $scoreData[] = [
                        'criterion_id' => $criterionId,
                        'score' => (float) $scoreInfo['score'],
                        'notes' => $scoreInfo['notes'] ?: null,
                    ];
                }
            }

            if ($this->evaluation && $this->evaluation->exists) {
                $this->evaluation->update($data);
                $this->evaluation->scores()->delete();
                foreach ($scoreData as $score) {
                    $this->evaluation->scores()->create($score);
                }
                $evaluation = $this->evaluation->fresh();
            } else {
                $evaluation = $service->create($data, $scoreData, auth()->user());
            }

            if ($shouldSubmit && $evaluation->status->value === 'draft') {
                $service->submit($evaluation);
            }

            session()->flash('success', $shouldSubmit ? __('تم تقديم التقييم بنجاح') : __('تم حفظ التقييم كمسودة'));
            $this->redirect(route('evaluations.list'), navigate: true);
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function render()
    {
        $branchId = $this->getActiveBranchId();
        $participants = Participant::with('person')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->get();
        $groups = TrainingGroup::orderBy('name_ar')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->get(['id', 'name_ar']);
        $criteria = EvaluationCriterion::active()->orderBy('sort_order')->get();

        return view('livewire.evaluations.evaluation-form', [
            'participants' => $participants,
            'groups' => $groups,
            'criteria' => $criteria,
        ]);
    }
}
