<?php

namespace App\Domain\Training\Services;

use App\Domain\Shared\Exceptions\InvalidStatusTransitionException;
use App\Domain\Training\Enums\EvaluationStatus;
use App\Domain\Training\Models\Evaluation;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class EvaluationService
{
    private const VALID_TRANSITIONS = [
        'draft' => ['submitted'],
        'submitted' => ['approved'],
        'approved' => ['shared'],
        'shared' => [],
    ];

    public function create(array $data, array $scores, User $evaluator): Evaluation
    {
        return DB::transaction(function () use ($data, $scores, $evaluator) {
            $evaluation = Evaluation::create(array_merge($data, [
                'evaluator_id' => $evaluator->id,
                'status' => 'draft',
            ]));

            foreach ($scores as $score) {
                $evaluation->scores()->create([
                    'criterion_id' => $score['criterion_id'],
                    'score' => $score['score'],
                    'notes' => $score['notes'] ?? null,
                ]);
            }

            return $evaluation->load('scores');
        });
    }

    public function submit(Evaluation $evaluation): Evaluation
    {
        $this->assertTransition($evaluation, EvaluationStatus::Submitted);

        return DB::transaction(function () use ($evaluation) {
            $evaluation->update(['status' => EvaluationStatus::Submitted->value]);
            return $evaluation->fresh();
        });
    }

    public function approve(Evaluation $evaluation, User $approver): Evaluation
    {
        $this->assertTransition($evaluation, EvaluationStatus::Approved);

        return DB::transaction(function () use ($evaluation, $approver) {
            $evaluation->update([
                'status' => EvaluationStatus::Approved->value,
                'approved_by' => $approver->id,
                'approved_at' => now(),
            ]);
            return $evaluation->fresh();
        });
    }

    public function share(Evaluation $evaluation): Evaluation
    {
        $this->assertTransition($evaluation, EvaluationStatus::Shared);

        return DB::transaction(function () use ($evaluation) {
            $evaluation->update([
                'status' => EvaluationStatus::Shared->value,
                'shared_at' => now(),
            ]);
            return $evaluation->fresh();
        });
    }

    private function assertTransition(Evaluation $evaluation, EvaluationStatus $target): void
    {
        $currentStatus = $evaluation->status->value;
        $allowed = self::VALID_TRANSITIONS[$currentStatus] ?? [];

        if (!in_array($target->value, $allowed)) {
            throw new InvalidStatusTransitionException(
                "Cannot transition from '{$currentStatus}' to '{$target->value}'"
            );
        }
    }
}
