<?php

namespace App\Domain\Training\Services;

use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class TrainingGroupService
{
    private const VALID_TRANSITIONS = [
        'forming' => ['active', 'cancelled'],
        'active' => ['full', 'on_hold', 'completed', 'cancelled'],
        'full' => ['active'],
        'on_hold' => ['active'],
        'completed' => [],
        'cancelled' => [],
    ];

    public function create(array $data, User $actor): TrainingGroup
    {
        return DB::transaction(function () use ($data, $actor) {
            $program = TrainingProgram::findOrFail($data['training_program_id']);

            return TrainingGroup::create(array_merge($data, [
                'max_capacity' => $data['max_capacity'] ?? $program->max_participants,
                'status' => 'forming',
                'status_changed_at' => now(),
                'created_by' => $actor->id,
            ]));
        });
    }

    public function update(TrainingGroup $group, array $data): TrainingGroup
    {
        return DB::transaction(function () use ($group, $data) {
            if (isset($data['code']) && $data['code'] !== $group->code) {
                $exists = TrainingGroup::where('code', $data['code'])
                    ->where('id', '!=', $group->id)
                    ->exists();
                if ($exists) {
                    throw new DomainException('هذا الكود مستخدم بالفعل');
                }
            }
            $group->update($data);
            return $group->fresh();
        });
    }

    public function changeStatus(TrainingGroup $group, string $newStatus, User $actor): TrainingGroup
    {
        return DB::transaction(function () use ($group, $newStatus, $actor) {
            $currentStatus = $group->status->value ?? $group->status;
            $allowed = self::VALID_TRANSITIONS[$currentStatus] ?? [];

            if (!in_array($newStatus, $allowed)) {
                throw new DomainException("لا يمكن تغيير حالة المجموعة من '{$currentStatus}' إلى '{$newStatus}'");
            }

            $group->update([
                'status' => $newStatus,
                'status_changed_at' => now(),
            ]);

            return $group->fresh();
        });
    }

    public function incrementCount(TrainingGroup $group): void
    {
        DB::transaction(function () use ($group) {
            $group->increment('current_count');
            if ($group->fresh()->current_count >= $group->max_capacity) {
                $group->update(['status' => 'full', 'status_changed_at' => now()]);
            }
        });
    }

    public function decrementCount(TrainingGroup $group): void
    {
        DB::transaction(function () use ($group) {
            $group->decrement('current_count');
            if ($group->status->value === 'full' && $group->fresh()->current_count < $group->max_capacity) {
                $group->update(['status' => 'active', 'status_changed_at' => now()]);
            }
        });
    }
}
