<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\Doctrine;

use App\Scolarite\Domain\Model\Evaluation\ClassStatistics;
use App\Scolarite\Domain\Model\Evaluation\EvaluationId;
use App\Scolarite\Domain\Repository\EvaluationStatisticsRepository;
use Doctrine\DBAL\Connection;
use Override;

final readonly class DoctrineEvaluationStatisticsRepository implements EvaluationStatisticsRepository
{
    public function __construct(
        private Connection $connection,
    ) {
    }

    #[Override]
    public function save(EvaluationId $evaluationId, ClassStatistics $statistics): void
    {
        $this->connection->executeStatement(
            'INSERT INTO evaluation_statistics (evaluation_id, average, min_grade, max_grade, median_grade, graded_count, updated_at)
             VALUES (:evaluation_id, :average, :min_grade, :max_grade, :median_grade, :graded_count, NOW())
             ON CONFLICT (evaluation_id) DO UPDATE SET
                 average = EXCLUDED.average,
                 min_grade = EXCLUDED.min_grade,
                 max_grade = EXCLUDED.max_grade,
                 median_grade = EXCLUDED.median_grade,
                 graded_count = EXCLUDED.graded_count,
                 updated_at = NOW()',
            [
                'evaluation_id' => (string) $evaluationId,
                'average' => $statistics->average,
                'min_grade' => $statistics->min,
                'max_grade' => $statistics->max,
                'median_grade' => $statistics->median,
                'graded_count' => $statistics->gradedCount,
            ],
        );
    }

    #[Override]
    public function findByEvaluation(EvaluationId $evaluationId): ?ClassStatistics
    {
        $row = $this->connection->fetchAssociative(
            'SELECT * FROM evaluation_statistics WHERE evaluation_id = :evaluation_id',
            ['evaluation_id' => (string) $evaluationId],
        );

        if ($row === false) {
            return null;
        }

        /** @var string|float|null $average */
        $average = $row['average'];
        /** @var string|float|null $minGrade */
        $minGrade = $row['min_grade'];
        /** @var string|float|null $maxGrade */
        $maxGrade = $row['max_grade'];
        /** @var string|float|null $medianGrade */
        $medianGrade = $row['median_grade'];
        /** @var string|int $gradedCount */
        $gradedCount = $row['graded_count'];

        return new ClassStatistics(
            average: $average !== null ? (float) $average : null,
            min: $minGrade !== null ? (float) $minGrade : null,
            max: $maxGrade !== null ? (float) $maxGrade : null,
            median: $medianGrade !== null ? (float) $medianGrade : null,
            gradedCount: (int) $gradedCount,
        );
    }

    #[Override]
    public function delete(EvaluationId $evaluationId): void
    {
        $this->connection->executeStatement(
            'DELETE FROM evaluation_statistics WHERE evaluation_id = :evaluation_id',
            ['evaluation_id' => (string) $evaluationId],
        );
    }
}
