<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Cache;

use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Repository\StudentAverageRepository;
use App\Shared\Domain\Tenant\TenantId;
use Override;
use Psr\Cache\CacheItemPoolInterface;

final readonly class CachingStudentAverageRepository implements StudentAverageRepository
{
    public function __construct(
        private StudentAverageRepository $inner,
        private CacheItemPoolInterface $cache,
    ) {
    }

    #[Override]
    public function saveSubjectAverage(
        TenantId $tenantId,
        UserId $studentId,
        SubjectId $subjectId,
        string $periodId,
        float $average,
        int $gradeCount,
    ): void {
        $this->inner->saveSubjectAverage($tenantId, $studentId, $subjectId, $periodId, $average, $gradeCount);

        // Invalider le cache des moyennes matières de l'élève
        $this->cache->deleteItem($this->subjectAveragesKey($studentId, $periodId, $tenantId));
    }

    #[Override]
    public function saveGeneralAverage(
        TenantId $tenantId,
        UserId $studentId,
        string $periodId,
        float $average,
    ): void {
        $this->inner->saveGeneralAverage($tenantId, $studentId, $periodId, $average);
    }

    #[Override]
    public function findSubjectAveragesForStudent(
        UserId $studentId,
        string $periodId,
        TenantId $tenantId,
    ): array {
        $key = $this->subjectAveragesKey($studentId, $periodId, $tenantId);
        $item = $this->cache->getItem($key);

        if ($item->isHit()) {
            /** @var list<float> $cached */
            $cached = $item->get();

            return $cached;
        }

        $averages = $this->inner->findSubjectAveragesForStudent($studentId, $periodId, $tenantId);

        $item->set($averages);
        $this->cache->save($item);

        return $averages;
    }

    #[Override]
    public function findDetailedSubjectAveragesForStudent(
        UserId $studentId,
        string $periodId,
        TenantId $tenantId,
    ): array {
        return $this->inner->findDetailedSubjectAveragesForStudent($studentId, $periodId, $tenantId);
    }

    #[Override]
    public function findGeneralAverageForStudent(
        UserId $studentId,
        string $periodId,
        TenantId $tenantId,
    ): ?float {
        return $this->inner->findGeneralAverageForStudent($studentId, $periodId, $tenantId);
    }

    #[Override]
    public function deleteSubjectAverage(
        UserId $studentId,
        SubjectId $subjectId,
        string $periodId,
        TenantId $tenantId,
    ): void {
        $this->inner->deleteSubjectAverage($studentId, $subjectId, $periodId, $tenantId);
        $this->cache->deleteItem($this->subjectAveragesKey($studentId, $periodId, $tenantId));
    }

    #[Override]
    public function deleteGeneralAverage(
        UserId $studentId,
        string $periodId,
        TenantId $tenantId,
    ): void {
        $this->inner->deleteGeneralAverage($studentId, $periodId, $tenantId);
    }

    private function subjectAveragesKey(UserId $studentId, string $periodId, TenantId $tenantId): string
    {
        return 'avg_' . $tenantId . '_' . $studentId . '_' . $periodId;
    }
}
