<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Exception\AffectationNotFoundException;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\TeacherAssignment\AssignmentStatus;
use App\Administration\Domain\Model\TeacherAssignment\TeacherAssignment;
use App\Administration\Domain\Model\TeacherAssignment\TeacherAssignmentId;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Domain\Repository\TeacherAssignmentRepository;
use App\Shared\Domain\Tenant\TenantId;
use Override;

final class InMemoryTeacherAssignmentRepository implements TeacherAssignmentRepository
{
    /** @var array<string, TeacherAssignment> */
    private array $byId = [];

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

    #[Override]
    public function get(TeacherAssignmentId $id, TenantId $tenantId): TeacherAssignment
    {
        $assignment = $this->findById($id, $tenantId);

        if ($assignment === null) {
            throw AffectationNotFoundException::withId($id);
        }

        return $assignment;
    }

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

        if ($assignment !== null && !$assignment->tenantId->equals($tenantId)) {
            return null;
        }

        return $assignment;
    }

    #[Override]
    public function findByTeacherClassSubject(
        UserId $teacherId,
        ClassId $classId,
        SubjectId $subjectId,
        AcademicYearId $academicYearId,
        TenantId $tenantId,
    ): ?TeacherAssignment {
        foreach ($this->byId as $assignment) {
            if ($assignment->tenantId->equals($tenantId)
                && $assignment->teacherId->equals($teacherId)
                && $assignment->classId->equals($classId)
                && $assignment->subjectId->equals($subjectId)
                && $assignment->academicYearId->equals($academicYearId)
                && $assignment->status === AssignmentStatus::ACTIVE
            ) {
                return $assignment;
            }
        }

        return null;
    }

    #[Override]
    public function findRemovedByTeacherClassSubject(
        UserId $teacherId,
        ClassId $classId,
        SubjectId $subjectId,
        AcademicYearId $academicYearId,
        TenantId $tenantId,
    ): ?TeacherAssignment {
        foreach ($this->byId as $assignment) {
            if ($assignment->tenantId->equals($tenantId)
                && $assignment->teacherId->equals($teacherId)
                && $assignment->classId->equals($classId)
                && $assignment->subjectId->equals($subjectId)
                && $assignment->academicYearId->equals($academicYearId)
                && $assignment->status === AssignmentStatus::REMOVED
            ) {
                return $assignment;
            }
        }

        return null;
    }

    #[Override]
    public function findActiveByTeacher(
        UserId $teacherId,
        TenantId $tenantId,
    ): array {
        $result = [];

        foreach ($this->byId as $assignment) {
            if ($assignment->teacherId->equals($teacherId)
                && $assignment->tenantId->equals($tenantId)
                && $assignment->status === AssignmentStatus::ACTIVE
            ) {
                $result[] = $assignment;
            }
        }

        return $result;
    }

    #[Override]
    public function findActiveByClass(
        ClassId $classId,
        TenantId $tenantId,
    ): array {
        $result = [];

        foreach ($this->byId as $assignment) {
            if ($assignment->classId->equals($classId)
                && $assignment->tenantId->equals($tenantId)
                && $assignment->status === AssignmentStatus::ACTIVE
            ) {
                $result[] = $assignment;
            }
        }

        return $result;
    }

    #[Override]
    public function findAllActiveByTenant(TenantId $tenantId): array
    {
        $result = [];

        foreach ($this->byId as $assignment) {
            if ($assignment->tenantId->equals($tenantId)
                && $assignment->status === AssignmentStatus::ACTIVE
            ) {
                $result[] = $assignment;
            }
        }

        return $result;
    }
}
