<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Exception\RenduNonTrouveException;
use App\Scolarite\Domain\Model\Homework\HomeworkId;
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmission;
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmissionId;
use App\Scolarite\Domain\Repository\HomeworkSubmissionRepository;
use App\Shared\Domain\Tenant\TenantId;

use function array_fill_keys;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_values;

use Override;

final class InMemoryHomeworkSubmissionRepository implements HomeworkSubmissionRepository
{
    /** @var array<string, HomeworkSubmission> */
    private array $byId = [];

    #[Override]
    public function save(HomeworkSubmission $submission): void
    {
        $this->byId[(string) $submission->id] = $submission;
    }

    #[Override]
    public function get(HomeworkSubmissionId $id, TenantId $tenantId): HomeworkSubmission
    {
        $submission = $this->findById($id, $tenantId);

        if ($submission === null) {
            throw RenduNonTrouveException::withId($id);
        }

        return $submission;
    }

    #[Override]
    public function findById(HomeworkSubmissionId $id, TenantId $tenantId): ?HomeworkSubmission
    {
        $submission = $this->byId[(string) $id] ?? null;

        if ($submission === null || !$submission->tenantId->equals($tenantId)) {
            return null;
        }

        return $submission;
    }

    #[Override]
    public function findByHomeworkAndStudent(
        HomeworkId $homeworkId,
        UserId $studentId,
        TenantId $tenantId,
    ): ?HomeworkSubmission {
        foreach ($this->byId as $submission) {
            if (
                $submission->homeworkId->equals($homeworkId)
                && $submission->studentId->equals($studentId)
                && $submission->tenantId->equals($tenantId)
            ) {
                return $submission;
            }
        }

        return null;
    }

    #[Override]
    public function findByHomework(HomeworkId $homeworkId, TenantId $tenantId): array
    {
        return array_values(array_filter(
            $this->byId,
            static fn (HomeworkSubmission $s): bool => $s->homeworkId->equals($homeworkId)
                && $s->tenantId->equals($tenantId),
        ));
    }

    #[Override]
    public function findStatusesByStudent(UserId $studentId, TenantId $tenantId, HomeworkId ...$homeworkIds): array
    {
        $ids = array_map(static fn (HomeworkId $id): string => (string) $id, $homeworkIds);
        $result = array_fill_keys($ids, null);

        foreach ($this->byId as $submission) {
            if (
                $submission->studentId->equals($studentId)
                && $submission->tenantId->equals($tenantId)
            ) {
                $hwId = (string) $submission->homeworkId;

                if (array_key_exists($hwId, $result)) {
                    $result[$hwId] = $submission->status->value;
                }
            }
        }

        return $result;
    }
}
