<?php

namespace Functional\Tracking\Services;

use Carbon\Carbon;
use Functional\Tracking\Enums\WorkoutSessionStatus;
use Functional\Tracking\Exceptions\WorkoutSessionAlreadyClosedException;
use Functional\Tracking\Models\SetLog;
use Functional\Tracking\Models\WorkoutSession;
use Functional\Users\Models\User;

/**
 * Cycle de vie d'une séance d'entraînement : démarrage, log de sets, complétion.
 * La complétion sauvegarde le statut "completed", ce qui déclenche WorkoutCompleted
 * (écouté par la couche streaks pour recalculer le streak de l'utilisateur).
 */
class WorkoutSessionService
{
    public function start(User $user, array $data): WorkoutSession
    {
        return WorkoutSession::create([
            'user_id' => $user->id,
            'routine_id' => $data['routine_id'] ?? null,
            'title' => $data['title'] ?? null,
            'started_at' => now(),
            'status' => WorkoutSessionStatus::Active,
        ]);
    }

    public function logSet(WorkoutSession $session, array $data): SetLog
    {
        if ($session->status->isTerminal()) {
            throw new WorkoutSessionAlreadyClosedException($session->id);
        }

        return $session->setLogs()->create([
            'exercise_id' => $data['exercise_id'],
            'set_number' => $data['set_number'],
            'reps' => $data['reps'] ?? null,
            'weight' => $data['weight'] ?? null,
            'rpe' => $data['rpe'] ?? null,
            'duration_seconds' => $data['duration_seconds'] ?? null,
            'distance_meters' => $data['distance_meters'] ?? null,
            'is_warmup' => $data['is_warmup'] ?? false,
            'is_completed' => true,
            'logged_at' => now(),
        ]);
    }

    public function complete(WorkoutSession $session, array $data): WorkoutSession
    {
        if ($session->status->isTerminal()) {
            throw new WorkoutSessionAlreadyClosedException($session->id);
        }

        $session->ended_at = isset($data['ended_at']) ? Carbon::parse($data['ended_at']) : now();
        $session->total_volume = $this->calculateTotalVolume($session);
        $session->status = WorkoutSessionStatus::Completed;
        $session->save(); // déclenche WorkoutCompleted (recalcul du streak, couche streaks)

        return $session->fresh('setLogs');
    }

    /** Volume total = somme(reps * poids) des séries effectives (hors échauffement). */
    private function calculateTotalVolume(WorkoutSession $session): float
    {
        return (float) $session->setLogs()
            ->where('is_warmup', false)
            ->get()
            ->sum(fn (SetLog $setLog) => (float) ($setLog->reps ?? 0) * (float) ($setLog->weight ?? 0));
    }
}
