<?php

namespace Functional\Tracking\Http\Controllers;

use Functional\Streaks\Models\Achievement;
use Functional\Streaks\Models\Streak;
use Functional\Tracking\Http\Requests\CompleteWorkoutSessionRequest;
use Functional\Tracking\Http\Requests\StoreSetLogRequest;
use Functional\Tracking\Http\Requests\StoreWorkoutSessionRequest;
use Functional\Tracking\Http\Resources\SetLogResource;
use Functional\Tracking\Http\Resources\WorkoutSessionResource;
use Functional\Tracking\Models\WorkoutSession;
use Functional\Tracking\Services\WorkoutSessionService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

/**
 * Séances d'entraînement de l'utilisateur authentifié (démarrage, consultation, log de sets, complétion).
 */
class SessionsController
{
    public function __construct(
        private readonly WorkoutSessionService $workoutSessionService,
    ) {
    }

    /** POST /api/sessions — démarre une séance (status=active). */
    public function store(StoreWorkoutSessionRequest $request): JsonResponse
    {
        $session = $this->workoutSessionService->start($request->user(), $request->validated());

        return (new WorkoutSessionResource($session))
            ->response()
            ->setStatusCode(Response::HTTP_CREATED);
    }

    /** GET /api/sessions/{session} — séance + setLogs + exercices planifiés de la routine. */
    public function show(int $session): WorkoutSessionResource
    {
        return new WorkoutSessionResource(
            $this->findForUser($session)->load(['setLogs', 'routine.routineExercises.exercise'])
        );
    }

    /** POST /api/sessions/{session}/sets — log un set. */
    public function storeSet(StoreSetLogRequest $request, int $session): JsonResponse
    {
        $setLog = $this->workoutSessionService->logSet($this->findForUser($session), $request->validated());

        return (new SetLogResource($setLog))
            ->response()
            ->setStatusCode(Response::HTTP_CREATED);
    }

    /**
     * POST /api/sessions/{session}/complete — termine la séance (déclenche WorkoutCompleted → streak).
     * Renvoie la séance, le streak recalculé et les achievements nouvellement débloqués.
     */
    public function complete(CompleteWorkoutSessionRequest $request, int $session): JsonResponse
    {
        $user = $request->user();
        $previouslyEarnedKeys = Achievement::query()->where('user_id', $user->id)->pluck('key');

        $workoutSession = $this->workoutSessionService->complete($this->findForUser($session), $request->validated());

        $streak = Streak::query()->where('user_id', $user->id)->first();
        $locale = $user->locale ?? 'fr';

        $unlockedAchievements = Achievement::query()
            ->where('user_id', $user->id)
            ->whereNotIn('key', $previouslyEarnedKeys)
            ->get()
            ->map(fn (Achievement $achievement) => [
                'key' => $achievement->key,
                'earned_at' => $achievement->earned_at,
                'label' => __("achievements.{$achievement->key}", [], $locale),
            ])
            ->values();

        return response()->json([
            'session' => new WorkoutSessionResource($workoutSession),
            'streak' => [
                'current' => $streak?->current_count ?? 0,
                'longest' => $streak?->longest_count ?? 0,
                'freezes_available' => $streak?->freezes_available ?? 0,
                'last_active_date' => optional($streak?->last_active_date)->toDateString(),
            ],
            'unlocked_achievements' => $unlockedAchievements,
        ]);
    }

    /** Charge la séance en la scopant strictement à l'utilisateur courant. */
    private function findForUser(int $sessionId): WorkoutSession
    {
        return WorkoutSession::query()
            ->where('user_id', auth()->id())
            ->findOrFail($sessionId);
    }
}
