<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\Game;
use App\Entity\GamePlayer;
use App\Entity\Turn;
use App\Enum\GameStatus;
use App\Repository\DartThrowRepository;
use App\Repository\GameRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/api/games')]
class ApiStatisticsController extends AbstractController
{
    public function __construct(
        private readonly GameRepository $gameRepository,
        private readonly DartThrowRepository $dartThrowRepository,
    ) {
    }

    #[Route('/{id}/statistics', name: 'api_game_statistics', methods: ['GET'])]
    public function show(string $id): JsonResponse
    {
        $game = $this->requireGame($id);

        if ($game->getStatus() !== GameStatus::FINISHED) {
            return $this->json([
                'message' => 'Statistics are only available for finished games.',
            ], Response::HTTP_BAD_REQUEST);
        }

        $players = $game->getPlayers()->toArray();
        usort($players, static fn (GamePlayer $a, GamePlayer $b): int => $a->getPosition() <=> $b->getPosition());

        $winner = null;
        $playerStatsById = [];
        foreach ($players as $player) {
            if ($player->isWinner()) {
                $winner = [
                    'id' => $player->getId(),
                    'name' => $player->getName(),
                ];
            }

            $playerStatsById[$player->getId()] = [
                'playerId' => $player->getId(),
                'name' => $player->getName(),
                'position' => $player->getPosition(),
                'isWinner' => $player->isWinner(),
                'turnsPlayed' => 0,
                'bustTurns' => 0,
                'dartsThrown' => 0,
                'totalScoredPoints' => 0,
                'averagePointsPerDart' => 0.0,
                'highestThrowPoints' => 0,
            ];
        }

        $turns = $game->getTurns()->toArray();
        $completedTurns = array_filter(
            $turns,
            static fn (Turn $turn): bool => $turn->getEndedAt() !== null,
        );

        foreach ($completedTurns as $turn) {
            $playerId = $turn->getPlayer()->getId();
            if (!isset($playerStatsById[$playerId])) {
                continue;
            }

            $playerStatsById[$playerId]['turnsPlayed']++;
            if ($turn->isBust()) {
                $playerStatsById[$playerId]['bustTurns']++;
            }
        }

        $throws = $this->dartThrowRepository->findAllForGameOrdered($game);
        $totalThrows = count($throws);
        $totalScoredPoints = 0;
        $highestThrowPoints = 0;

        foreach ($throws as $throw) {
            $points = $throw->getScoredPoints();
            $playerId = $throw->getPlayer()->getId();

            $totalScoredPoints += $points;
            $highestThrowPoints = max($highestThrowPoints, $points);

            if (!isset($playerStatsById[$playerId])) {
                continue;
            }

            $playerStatsById[$playerId]['dartsThrown']++;
            $playerStatsById[$playerId]['totalScoredPoints'] += $points;
            $playerStatsById[$playerId]['highestThrowPoints'] = max(
                $playerStatsById[$playerId]['highestThrowPoints'],
                $points,
            );
        }

        foreach ($playerStatsById as $playerId => $playerStats) {
            $playerStatsById[$playerId]['averagePointsPerDart'] = $this->calculateAverage(
                $playerStats['totalScoredPoints'],
                $playerStats['dartsThrown'],
            );
        }

        $durationSeconds = null;
        if ($game->getStartedAt() instanceof \DateTimeImmutable && $game->getFinishedAt() instanceof \DateTimeImmutable) {
            $durationSeconds = max(0, $game->getFinishedAt()->getTimestamp() - $game->getStartedAt()->getTimestamp());
        }

        return $this->json([
            'statistics' => [
                'gameId' => $game->getId(),
                'winner' => $winner,
                'modeName' => $game->getMode()->getName(),
                'startedAt' => $game->getStartedAt()?->format(\DateTimeInterface::ATOM),
                'finishedAt' => $game->getFinishedAt()?->format(\DateTimeInterface::ATOM),
                'durationSeconds' => $durationSeconds,
                'totalTurns' => count($completedTurns),
                'totalThrows' => $totalThrows,
                'totalScoredPoints' => $totalScoredPoints,
                'averagePointsPerDart' => $this->calculateAverage($totalScoredPoints, $totalThrows),
                'highestThrowPoints' => $highestThrowPoints,
                'playerStats' => array_values($playerStatsById),
            ],
        ]);
    }

    private function requireGame(string $id): Game
    {
        $game = $this->gameRepository->findWithPlayers($id);
        if (!$game instanceof Game) {
            throw $this->createNotFoundException('Game not found');
        }

        return $game;
    }

    private function calculateAverage(int $totalPoints, int $totalThrows): float
    {
        if ($totalThrows <= 0) {
            return 0.0;
        }

        return round($totalPoints / $totalThrows, 2);
    }
}
