<?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\Tests\Dto;

use App\Dto\ProfileStatsDto;
use App\Entity\UserStats;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;

/**
 * Class ProfileStatsDtoTest
 *
 * @package  App\Tests\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. 21.
 */
#[TestDox('Profile Stats Dto')]
class ProfileStatsDtoTest extends TestCase
{
    #[Test]
    #[TestDox('From user stats with valid stats')]
    public function fromUserStatsWithValidStats(): void
    {
        $userStats = new UserStats();
        $userStats->userId = 1;
        $userStats->totalGames = 100;
        $userStats->wins = 60;
        $userStats->losses = 30;
        $userStats->draws = 10;
        $userStats->totalMines = 500;
        $userStats->totalBonusPoints = '150.5';
        $userStats->avgBonus = '2.5';
        $userStats->bestChain = 5;
        $userStats->blindHits = 20;
        $userStats->edgeMines = 15;
        $userStats->gamesWithScores = 90;

        $dto = ProfileStatsDto::fromUserStats($userStats);

        $this->assertSame(100, $dto->total);
        $this->assertSame(60, $dto->wins);
        $this->assertSame(30, $dto->losses);
        $this->assertSame(10, $dto->draws);
        $this->assertSame(500, $dto->minesHit);
        $this->assertSame(67, $dto->winRate); // 60/90 * 100 = 67
        $this->assertSame(6, $dto->avgScore); // 500/90 = 5.56 -> 6
        $this->assertSame(150.5, $dto->bonusPoints);
        $this->assertSame(2.5, $dto->avgBonus);
        $this->assertSame(5, $dto->bestChain);
        $this->assertSame(20, $dto->blindHits);
        $this->assertSame(15, $dto->edgeMines);
    }

    #[Test]
    #[TestDox('From user stats with null returns empty')]
    public function fromUserStatsWithNullReturnsEmpty(): void
    {
        $dto = ProfileStatsDto::fromUserStats(null);

        $this->assertSame(0, $dto->total);
        $this->assertSame(0, $dto->wins);
        $this->assertSame(0, $dto->losses);
        $this->assertSame(0, $dto->draws);
        $this->assertSame(0, $dto->minesHit);
        $this->assertSame(0, $dto->winRate);
        $this->assertSame(0, $dto->avgScore);
        $this->assertSame(0.0, $dto->bonusPoints);
        $this->assertSame(0.0, $dto->avgBonus);
        $this->assertSame(0, $dto->bestChain);
        $this->assertSame(0, $dto->blindHits);
        $this->assertSame(0, $dto->edgeMines);
    }

    #[Test]
    #[TestDox('Empty returns default values')]
    public function emptyReturnsDefaultValues(): void
    {
        $dto = ProfileStatsDto::empty();

        $this->assertSame(0, $dto->total);
        $this->assertSame(0, $dto->wins);
        $this->assertSame(0, $dto->losses);
        $this->assertSame(0, $dto->draws);
        $this->assertSame(0, $dto->minesHit);
        $this->assertSame(0, $dto->winRate);
        $this->assertSame(0, $dto->avgScore);
        $this->assertSame(0.0, $dto->bonusPoints);
        $this->assertSame(0.0, $dto->avgBonus);
        $this->assertSame(0, $dto->bestChain);
        $this->assertSame(0, $dto->blindHits);
        $this->assertSame(0, $dto->edgeMines);
    }

    #[Test]
    #[TestDox('Win rate calculation with no games with scores')]
    public function winRateCalculationWithNoGamesWithScores(): void
    {
        $userStats = new UserStats();
        $userStats->totalGames = 10;
        $userStats->wins = 5;
        $userStats->losses = 5;
        $userStats->draws = 0;
        $userStats->gamesWithScores = 0;

        $dto = ProfileStatsDto::fromUserStats($userStats);

        $this->assertSame(0, $dto->winRate);
    }

    #[Test]
    #[TestDox('Avg score calculation with no games with scores')]
    public function avgScoreCalculationWithNoGamesWithScores(): void
    {
        $userStats = new UserStats();
        $userStats->totalMines = 100;
        $userStats->gamesWithScores = 0;

        $dto = ProfileStatsDto::fromUserStats($userStats);

        $this->assertSame(0, $dto->avgScore);
    }
}
