<?php
namespace App\Services;

use App\Models\Mission;
use App\Models\Besoin;
use App\Models\Candidat;
use App\Models\Remplacement;
use App\Models\User;
use App\Enums\StatutMission;
use App\Enums\StatutCandidat;
use App\Enums\StatutBesoin;
use App\Exceptions\TransitionStatutInvalideException;
use Illuminate\Support\Facades\DB;

class MissionService
{
    public function __construct(
        private readonly ReferenceGeneratorService $referenceGenerator,
        private readonly StatusLogService $statusLogService
    ) {}

    public function creerMission(array $data, User $adminUser): Mission
    {
        $besoin = Besoin::findOrFail($data['besoin_id']);
        $candidat = Candidat::findOrFail($data['candidat_id']);

        $candidatStatut = $candidat->statut instanceof StatutCandidat ? $candidat->statut->value : $candidat->statut;
        if ($candidatStatut !== StatutCandidat::DISPONIBLE->value) {
            throw new TransitionStatutInvalideException("Le candidat n'est pas disponible");
        }

        $besoinStatut = $besoin->statut instanceof StatutBesoin ? $besoin->statut->value : $besoin->statut;
        if (!in_array($besoinStatut, [StatutBesoin::CONTRAT_SIGNE->value, StatutBesoin::PROPOSITION_FAITE->value])) {
            throw new TransitionStatutInvalideException("Le besoin n'est pas dans un statut éligible");
        }

        return DB::transaction(function () use ($besoin, $candidat, $data, $adminUser) {
            $mission = Mission::create([
                'reference' => $this->referenceGenerator->genererReferenceMission(),
                'client_id' => $besoin->client_id,
                'besoin_id' => $besoin->id,
                'candidat_id' => $candidat->id,
                'assigne_par' => $adminUser->id,
                'type_service' => $besoin->type_service instanceof \App\Enums\TypeService ? $besoin->type_service->value : $besoin->type_service,
                'date_debut' => $data['date_debut'],
                'date_fin_prevue' => $data['date_fin_prevue'] ?? null,
                'salaire_mensuel' => $data['salaire_mensuel'],
                'tarif_agence' => $data['tarif_agence'],
                'frequence_paiement' => $data['frequence_paiement'],
                'statut' => StatutMission::ACTIVE->value,
            ]);

            $this->statusLogService->log($mission, StatutMission::ACTIVE->value, null);
            
            $candidat->update(['statut' => StatutCandidat::EN_MISSION->value]);
            $this->statusLogService->log($candidat, StatutCandidat::EN_MISSION->value, null);

            $besoin->update(['statut' => StatutBesoin::MISSION_EN_COURS->value]);
            $this->statusLogService->log($besoin, StatutBesoin::MISSION_EN_COURS->value, null);

            return $mission->load(['candidat.user', 'client', 'besoin.client', 'besoin.ville']);
        });
    }

    public function changerStatutMission(string $reference, string $nouveauStatut, ?string $motif, User $adminUser): Mission
    {
        $mission = Mission::where('reference', $reference)->firstOrFail();
        
        $currentStatut = $mission->statut instanceof StatutMission ? $mission->statut->value : $mission->statut;
        
        $validTransitions = [
            'planifiee' => ['active', 'annulee'],
            'active' => ['suspendue', 'terminee', 'annulee'],
            'suspendue' => ['active', 'terminee', 'annulee'],
            'terminee' => [],
            'annulee' => [],
        ];

        if (!in_array($nouveauStatut, $validTransitions[$currentStatut] ?? [])) {
            throw new TransitionStatutInvalideException("Transition invalide de {$currentStatut} vers {$nouveauStatut}");
        }

        return DB::transaction(function () use ($mission, $nouveauStatut, $motif, $adminUser) {
            $candidat = $mission->candidat;

            if ($nouveauStatut === StatutMission::TERMINEE->value || $nouveauStatut === StatutMission::ANNULEE->value) {
                $candidat->update(['statut' => StatutCandidat::DISPONIBLE->value]);
                $this->statusLogService->log($candidat, StatutCandidat::DISPONIBLE->value, $motif);
            }

            $mission->update(['statut' => $nouveauStatut, 'motif_fin' => $motif]);
            $this->statusLogService->log($mission, $nouveauStatut, $motif);

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

    public function supprimerMission(string $reference): void
    {
        $mission = Mission::where('reference', $reference)->firstOrFail();
        
        $missionStatut = $mission->statut instanceof StatutMission ? $mission->statut->value : $mission->statut;
        if ($missionStatut === StatutMission::ACTIVE->value) {
            throw new \InvalidArgumentException("Impossible de supprimer une mission active");
        }

        $mission->delete();
    }

    public function creerRemplacement(string $reference, array $data, User $adminUser): Remplacement
    {
        $mission = Mission::where('reference', $reference)->firstOrFail();
        
        $missionStatut = $mission->statut instanceof StatutMission ? $mission->statut->value : $mission->statut;
        if ($missionStatut !== StatutMission::ACTIVE->value) {
            throw new \InvalidArgumentException("La mission doit être active pour effectuer un remplacement");
        }

        $nouveauCandidat = Candidat::findOrFail($data['nouveau_candidat_id']);
        
        $nouveauCandidatStatut = $nouveauCandidat->statut instanceof StatutCandidat ? $nouveauCandidat->statut->value : $nouveauCandidat->statut;
        if ($nouveauCandidatStatut !== StatutCandidat::DISPONIBLE->value) {
            throw new TransitionStatutInvalideException("Le nouveau candidat n'est pas disponible");
        }

        return DB::transaction(function () use ($mission, $nouveauCandidat, $data, $adminUser) {
            $ancienCandidatId = $mission->candidat_id;

            $remplacement = Remplacement::create([
                'mission_id' => $mission->id,
                'ancien_candidat_id' => $ancienCandidatId,
                'nouveau_candidat_id' => $nouveauCandidat->id,
                'motif' => $data['motif'],
                'remplace_par' => $adminUser->id,
                'date_remplacement' => now(),
            ]);

            Candidat::where('id', $ancienCandidatId)->update(['statut' => StatutCandidat::DISPONIBLE->value]);
            $this->statusLogService->log(Candidat::find($ancienCandidatId), StatutCandidat::DISPONIBLE->value, $data['motif']);

            $nouveauCandidat->update(['statut' => StatutCandidat::EN_MISSION->value]);
            $this->statusLogService->log($nouveauCandidat, StatutCandidat::EN_MISSION->value, $data['motif']);

            $mission->update(['candidat_id' => $nouveauCandidat->id]);

            return $remplacement;
        });
    }
}
