<?php declare(strict_types=1);
/**
 * This file is part of the SplendidBear Websites' projects.
 *
 * Copyright (c) 2026 @ www.splendidbear.org
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Dto;

use App\Entity\User;
use App\Repository\PlayedGameRepository;
use DateTime;

/**
 * Class ProfileChartDataFactory
 *
 * @package  App\Dto
 * @author   Lang <https://www.splendidbear.org>
 * @category Class
 * @license  https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
 * @link     www.splendidbear.org
 * @since    2026. 04. 20.
 */
readonly final class ProfileChartDataFactory
{
    public function __construct(private PlayedGameRepository $repo) { }

    public function buildChartData(User $user, int $userId, ProfileStatsDto $stats): ProfileChartDataDto
    {
        $monthlyData = $this->buildMonthlyData($user, $userId);

        return new ProfileChartDataDto(
            months: array_column(array_values($monthlyData), 'label'),
            wins: array_column(array_values($monthlyData), 'wins'),
            losses: array_column(array_values($monthlyData), 'losses'),
            draws: array_column(array_values($monthlyData), 'draws'),
            pieWins: $stats->wins,
            pieLosses: $stats->losses,
            pieDraws: $stats->draws,
            recentGames: $this->buildRecentGamesSeries($user, $userId),
        );
    }

    private function buildMonthlyData(User $user, int $userId): array
    {
        $monthlyData = [];

        for ($i = 5; $i >= 0; $i--) {
            $dt = new DateTime("first day of -$i months midnight");
            $key = $dt->format('Y-m');
            $monthlyData[$key] = ['label' => $dt->format('M'), 'wins' => 0, 'losses' => 0, 'draws' => 0];
        }

        $since = new DateTime('first day of -5 months midnight');
        $recentGames = $this->repo->findFinishedForUserSince($user, $since);

        foreach ($recentGames as $game) {
            if (!$game->updated) {
                continue;
            }

            $month = $game->updated->format('Y-m');
            if (!isset($monthlyData[$month])) {
                continue;
            }

            $isRed = $game->red?->id === $userId;
            $myPts = $isRed ? $game->redPoints : $game->bluePoints;
            $oppPts = $isRed ? $game->bluePoints : $game->redPoints;
            $resign = $game->resign;
            $myColor = $isRed ? 'red' : 'blue';
            $oppColor = $isRed ? 'blue' : 'red';

            $result = 'draws';
            if ($resign === $myColor) {
                $result = 'losses';
            } elseif ($resign === $oppColor) {
                $result = 'wins';
            } elseif ($myPts !== null && $oppPts !== null) {
                if ($myPts > $oppPts) $result = 'wins';
                elseif ($myPts < $oppPts) $result = 'losses';
            }

            $monthlyData[$month][$result]++;
        }

        return $monthlyData;
    }

    private function buildRecentGamesSeries(User $user, int $userId): array
    {
        $recent = $this->repo->findRecentFinishedForUser($user, 15);
        $recent = array_reverse($recent);

        $labels = [];
        $mines = [];
        $bonus = [];

        foreach ($recent as $i => $game) {
            $isRed = $game->red?->id === $userId;
            $labels[] = '#' . ($i + 1);
            $mines[] = (int)($isRed ? $game->redPoints : $game->bluePoints);
            $bonus[] = (float)($isRed ? $game->redBonusPoints : $game->blueBonusPoints) ?: 0;
        }

        return ['labels' => $labels, 'mines' => $mines, 'bonus' => $bonus];
    }
}
