<?php

declare(strict_types=1);

namespace App\Tests\Functional\Scolarite\Api;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Scolarite\Domain\Model\Homework\Homework;
use App\Scolarite\Domain\Model\Homework\HomeworkId;
use App\Scolarite\Domain\Model\Homework\HomeworkStatus;
use App\Scolarite\Domain\Repository\HomeworkRepository;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use Doctrine\DBAL\Connection;

use const JSON_THROW_ON_ERROR;

use PHPUnit\Framework\Attributes\Test;
use Ramsey\Uuid\Uuid;

/**
 * Tests for homework API endpoints.
 *
 * @see Story 5.1 - Création de Devoirs
 */
final class HomeworkEndpointsTest extends ApiTestCase
{
    /**
     * Opt-in for API Platform 5.0 behavior where kernel boot is explicit.
     *
     * @see https://github.com/api-platform/core/issues/6971
     */
    protected static ?bool $alwaysBootKernel = true;

    private const string TENANT_ID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
    private const string OWNER_TEACHER_ID = '550e8400-e29b-41d4-a716-446655440000';
    private const string OTHER_TEACHER_ID = '660e8400-e29b-41d4-a716-446655440001';
    private const string CLASS_ID = '550e8400-e29b-41d4-a716-776655440001';
    private const string SUBJECT_ID = '550e8400-e29b-41d4-a716-886655440001';
    private const string HOMEWORK_ID = '550e8400-e29b-41d4-a716-996655440001';
    private const string DELETED_HOMEWORK_ID = '550e8400-e29b-41d4-a716-aa6655440001';
    private const string TARGET_CLASS_ID = '550e8400-e29b-41d4-a716-776655440002';

    protected function setUp(): void
    {
        parent::setUp();
        $this->createFixtures();
    }

    protected function tearDown(): void
    {
        $container = static::getContainer();
        /** @var Connection $connection */
        $connection = $container->get(Connection::class);
        $connection->executeStatement('DELETE FROM homework WHERE tenant_id = :tid', ['tid' => self::TENANT_ID]);
        $connection->executeStatement('DELETE FROM homework_rules WHERE tenant_id = :tid', ['tid' => self::TENANT_ID]);
        $connection->executeStatement('DELETE FROM school_classes WHERE id IN (:id1, :id2)', ['id1' => self::CLASS_ID, 'id2' => self::TARGET_CLASS_ID]);
        $connection->executeStatement('DELETE FROM subjects WHERE id = :id', ['id' => self::SUBJECT_ID]);
        $connection->executeStatement('DELETE FROM users WHERE id IN (:o, :t)', ['o' => self::OWNER_TEACHER_ID, 't' => self::OTHER_TEACHER_ID]);

        parent::tearDown();
    }

    private function createFixtures(): void
    {
        $container = static::getContainer();
        /** @var Connection $connection */
        $connection = $container->get(Connection::class);

        $schoolId = '550e8400-e29b-41d4-a716-ff6655440001';
        $academicYearId = '550e8400-e29b-41d4-a716-ff6655440002';

        $connection->executeStatement(
            "INSERT INTO users (id, tenant_id, email, hashed_password, first_name, last_name, roles, statut, created_at, updated_at)
             VALUES (:id, :tid, 'owner-hw@test.local', '', 'Owner', 'Teacher', '[\"ROLE_PROF\"]', 'active', NOW(), NOW())
             ON CONFLICT (id) DO NOTHING",
            ['id' => self::OWNER_TEACHER_ID, 'tid' => self::TENANT_ID],
        );
        $connection->executeStatement(
            "INSERT INTO users (id, tenant_id, email, hashed_password, first_name, last_name, roles, statut, created_at, updated_at)
             VALUES (:id, :tid, 'other-hw@test.local', '', 'Other', 'Teacher', '[\"ROLE_PROF\"]', 'active', NOW(), NOW())
             ON CONFLICT (id) DO NOTHING",
            ['id' => self::OTHER_TEACHER_ID, 'tid' => self::TENANT_ID],
        );
        $connection->executeStatement(
            "INSERT INTO school_classes (id, tenant_id, school_id, academic_year_id, name, status, created_at, updated_at)
             VALUES (:id, :tid, :sid, :ayid, 'Test-HW-Class', 'active', NOW(), NOW())
             ON CONFLICT (id) DO NOTHING",
            ['id' => self::CLASS_ID, 'tid' => self::TENANT_ID, 'sid' => $schoolId, 'ayid' => $academicYearId],
        );
        $connection->executeStatement(
            "INSERT INTO subjects (id, tenant_id, school_id, name, code, status, created_at, updated_at)
             VALUES (:id, :tid, :sid, 'Test-HW-Subject', 'THW', 'active', NOW(), NOW())
             ON CONFLICT (id) DO NOTHING",
            ['id' => self::SUBJECT_ID, 'tid' => self::TENANT_ID, 'sid' => $schoolId],
        );
        $connection->executeStatement(
            "INSERT INTO school_classes (id, tenant_id, school_id, academic_year_id, name, status, created_at, updated_at)
             VALUES (:id, :tid, :sid, :ayid, 'Test-HW-Target-Class', 'active', NOW(), NOW())
             ON CONFLICT (id) DO NOTHING",
            ['id' => self::TARGET_CLASS_ID, 'tid' => self::TENANT_ID, 'sid' => $schoolId, 'ayid' => $academicYearId],
        );
    }

    // =========================================================================
    // Security - Without tenant (404)
    // =========================================================================

    #[Test]
    public function getHomeworkListReturns404WithoutTenant(): void
    {
        $client = static::createClient();

        $client->request('GET', '/api/homework', [
            'headers' => [
                'Host' => 'localhost',
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    #[Test]
    public function createHomeworkReturns404WithoutTenant(): void
    {
        $client = static::createClient();

        $client->request('POST', '/api/homework', [
            'headers' => [
                'Host' => 'localhost',
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir de maths',
                'dueDate' => '2026-06-15',
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    #[Test]
    public function updateHomeworkReturns404WithoutTenant(): void
    {
        $client = static::createClient();

        $client->request('PATCH', '/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Host' => 'localhost',
                'Accept' => 'application/json',
                'Content-Type' => 'application/merge-patch+json',
            ],
            'json' => [
                'title' => 'Titre modifié',
                'dueDate' => '2026-06-20',
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    #[Test]
    public function deleteHomeworkReturns404WithoutTenant(): void
    {
        $client = static::createClient();

        $client->request('DELETE', '/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Host' => 'localhost',
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    // =========================================================================
    // Security - Without authentication (401)
    // =========================================================================

    #[Test]
    public function getHomeworkListReturns401WithoutAuthentication(): void
    {
        $client = static::createClient();

        $client->request('GET', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    #[Test]
    public function createHomeworkReturns401WithoutAuthentication(): void
    {
        $client = static::createClient();

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir de maths',
                'dueDate' => '2026-06-15',
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    #[Test]
    public function updateHomeworkReturns401WithoutAuthentication(): void
    {
        $client = static::createClient();

        $client->request('PATCH', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/merge-patch+json',
            ],
            'json' => [
                'title' => 'Titre modifié',
                'dueDate' => '2026-06-20',
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    #[Test]
    public function deleteHomeworkReturns401WithoutAuthentication(): void
    {
        $client = static::createClient();

        $client->request('DELETE', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    // =========================================================================
    // 5.1-FUNC-005 (P1) - POST /homework with empty title -> 422
    // =========================================================================

    #[Test]
    public function createHomeworkWithEmptyTitleReturns422(): void
    {
        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => '',
                'dueDate' => '2026-06-15',
            ],
        ]);

        self::assertResponseStatusCodeSame(422);
    }

    // =========================================================================
    // 5.1-FUNC-006 (P1) - POST /homework with past due date -> 400
    // =========================================================================

    #[Test]
    public function createHomeworkWithPastDueDateReturns400(): void
    {
        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir de maths',
                'dueDate' => '2020-01-01',
            ],
        ]);

        self::assertResponseStatusCodeSame(400);
    }

    // =========================================================================
    // 5.1-FUNC-007 (P0) - PATCH /homework/{id} by non-owner -> 403
    // =========================================================================

    #[Test]
    public function updateHomeworkByNonOwnerReturns403(): void
    {
        $this->persistHomework(self::HOMEWORK_ID, HomeworkStatus::PUBLISHED);

        $client = $this->createAuthenticatedClient(self::OTHER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('PATCH', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/merge-patch+json',
            ],
            'json' => [
                'title' => 'Titre piraté',
                'dueDate' => '2026-06-20',
            ],
        ]);

        self::assertResponseStatusCodeSame(403);
    }

    // =========================================================================
    // 5.1-FUNC-008 (P1) - PATCH /homework/{id} on deleted homework -> 400
    // =========================================================================

    #[Test]
    public function updateDeletedHomeworkReturns400(): void
    {
        $this->persistHomework(self::DELETED_HOMEWORK_ID, HomeworkStatus::DELETED);

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('PATCH', 'http://ecole-alpha.classeo.local/api/homework/' . self::DELETED_HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/merge-patch+json',
            ],
            'json' => [
                'title' => 'Titre modifié',
                'dueDate' => '2026-06-20',
            ],
        ]);

        self::assertResponseStatusCodeSame(400);
    }

    // =========================================================================
    // 5.1-FUNC-009 (P0) - DELETE /homework/{id} by non-owner -> 403
    // =========================================================================

    #[Test]
    public function deleteHomeworkByNonOwnerReturns403(): void
    {
        $this->persistHomework(self::HOMEWORK_ID, HomeworkStatus::PUBLISHED);

        $client = $this->createAuthenticatedClient(self::OTHER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('DELETE', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(403);
    }

    // =========================================================================
    // 5.1-FUNC-010 (P1) - DELETE /homework/{id} on already deleted -> 400
    // =========================================================================

    #[Test]
    public function deleteAlreadyDeletedHomeworkReturns400(): void
    {
        $this->persistHomework(self::DELETED_HOMEWORK_ID, HomeworkStatus::DELETED);

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('DELETE', 'http://ecole-alpha.classeo.local/api/homework/' . self::DELETED_HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(400);
    }

    // =========================================================================
    // 5.2-FUNC-001 (P1) - POST /homework/{id}/duplicate without tenant -> 404
    // =========================================================================

    #[Test]
    public function duplicateHomeworkReturns404WithoutTenant(): void
    {
        $client = static::createClient();

        $client->request('POST', '/api/homework/' . self::HOMEWORK_ID . '/duplicate', [
            'headers' => [
                'Host' => 'localhost',
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'targetClassIds' => [self::TARGET_CLASS_ID],
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    // =========================================================================
    // 5.2-FUNC-002 (P1) - POST /homework/{id}/duplicate without auth -> 401
    // =========================================================================

    #[Test]
    public function duplicateHomeworkReturns401WithoutAuthentication(): void
    {
        $client = static::createClient();

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID . '/duplicate', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'targetClassIds' => [self::TARGET_CLASS_ID],
            ],
        ]);

        self::assertResponseStatusCodeSame(401);
    }

    // =========================================================================
    // 5.2-FUNC-003 (P1) - POST /homework/{id}/duplicate empty classes -> 400
    // =========================================================================

    #[Test]
    public function duplicateHomeworkReturns400WithEmptyTargetClasses(): void
    {
        $this->persistHomework(self::HOMEWORK_ID, HomeworkStatus::PUBLISHED);

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID . '/duplicate', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'targetClassIds' => [],
            ],
        ]);

        self::assertResponseStatusCodeSame(400);
    }

    // =========================================================================
    // 5.2-FUNC-004 (P1) - POST /homework/{id}/duplicate not found -> 404
    // =========================================================================

    #[Test]
    public function duplicateHomeworkReturns404WhenHomeworkNotFound(): void
    {
        $nonExistentId = '00000000-0000-0000-0000-000000000099';

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework/' . $nonExistentId . '/duplicate', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'targetClassIds' => [self::TARGET_CLASS_ID],
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    // =========================================================================
    // 5.2-FUNC-005 (P1) - POST /homework/{id}/duplicate non-owner -> 404
    // =========================================================================

    #[Test]
    public function duplicateHomeworkReturns404WhenTeacherNotOwner(): void
    {
        $this->persistHomework(self::HOMEWORK_ID, HomeworkStatus::PUBLISHED);

        $client = $this->createAuthenticatedClient(self::OTHER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID . '/duplicate', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'targetClassIds' => [self::TARGET_CLASS_ID],
            ],
        ]);

        self::assertResponseStatusCodeSame(404);
    }

    // =========================================================================
    // 5.4-FUNC-001 (P2) - GET /homework/{id} with rule override -> hasRuleOverride = true
    // =========================================================================

    #[Test]
    public function getHomeworkShowsHasRuleOverrideTrue(): void
    {
        $this->persistHomeworkWithRuleOverride(self::HOMEWORK_ID);

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('GET', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(200);
        self::assertJsonContains(['hasRuleOverride' => true]);
    }

    // =========================================================================
    // 5.4-FUNC-002 (P2) - GET /homework/{id} without rule override -> hasRuleOverride = false
    // =========================================================================

    #[Test]
    public function getHomeworkShowsHasRuleOverrideFalse(): void
    {
        $this->persistHomework(self::HOMEWORK_ID, HomeworkStatus::PUBLISHED);

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $client->request('GET', 'http://ecole-alpha.classeo.local/api/homework/' . self::HOMEWORK_ID, [
            'headers' => [
                'Accept' => 'application/json',
            ],
        ]);

        self::assertResponseStatusCodeSame(200);
        self::assertJsonContains(['hasRuleOverride' => false]);
    }

    // =========================================================================
    // 5.4-FUNC-003 (P1) - POST /homework with soft rules violated → 409 with warnings
    // =========================================================================

    #[Test]
    public function createHomeworkReturns409WhenSoftRulesViolated(): void
    {
        $this->persistSoftRulesWithMinimumDelay(7);
        $this->seedTeacherAssignment();

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        // Due date tomorrow = violates 7-day minimum_delay
        $tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir test 409',
                'dueDate' => $tomorrow,
            ],
        ]);

        self::assertResponseStatusCodeSame(409);
        $json = $client->getResponse()->toArray(false);
        self::assertSame('homework_rules_warning', $json['type']);
        self::assertNotEmpty($json['warnings']);
        self::assertSame('minimum_delay', $json['warnings'][0]['ruleType']);
    }

    // =========================================================================
    // 5.4-FUNC-004 (P1) - POST /homework with acknowledgeWarning → 201 created
    // =========================================================================

    #[Test]
    public function createHomeworkReturns201WhenSoftRulesAcknowledged(): void
    {
        $this->persistSoftRulesWithMinimumDelay(7);
        $this->seedTeacherAssignment();

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir acknowledge',
                'dueDate' => $tomorrow,
                'acknowledgeWarning' => true,
            ],
        ]);

        self::assertResponseStatusCodeSame(201);
        self::assertJsonContains([
            'title' => 'Devoir acknowledge',
            'hasRuleOverride' => true,
        ]);
    }

    // =========================================================================
    // 5.5-FUNC-001 (P0) - POST /homework with hard rules violated → 422 with blocked response
    // =========================================================================

    #[Test]
    public function createHomeworkReturns422WhenHardRulesViolated(): void
    {
        $this->persistHardRulesWithMinimumDelay(7);
        $this->seedTeacherAssignment();

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir test 422',
                'dueDate' => $tomorrow,
            ],
        ]);

        self::assertResponseStatusCodeSame(422);
        $json = $client->getResponse()->toArray(false);
        self::assertSame('homework_rules_blocked', $json['type']);
        self::assertNotEmpty($json['warnings']);
        self::assertSame('minimum_delay', $json['warnings'][0]['ruleType']);
        self::assertArrayHasKey('suggestedDates', $json);
        self::assertArrayHasKey('exceptionRequestPath', $json);
    }

    // =========================================================================
    // 5.5-FUNC-002 (P0) - POST /homework with hard rules violated + acknowledgeWarning → still 422
    // =========================================================================

    #[Test]
    public function createHomeworkReturns422EvenWhenHardRulesAcknowledged(): void
    {
        $this->persistHardRulesWithMinimumDelay(7);
        $this->seedTeacherAssignment();

        $client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);

        $tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');

        $client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'json' => [
                'classId' => self::CLASS_ID,
                'subjectId' => self::SUBJECT_ID,
                'title' => 'Devoir bypass hard',
                'dueDate' => $tomorrow,
                'acknowledgeWarning' => true,
            ],
        ]);

        self::assertResponseStatusCodeSame(422);
        $json = $client->getResponse()->toArray(false);
        self::assertSame('homework_rules_blocked', $json['type']);
    }

    // =========================================================================
    // Helpers
    // =========================================================================

    private function createAuthenticatedClient(string $userId, array $roles): \ApiPlatform\Symfony\Bundle\Test\Client
    {
        $client = static::createClient();

        $user = new SecurityUser(
            userId: UserId::fromString($userId),
            email: 'teacher@classeo.local',
            hashedPassword: '',
            tenantId: TenantId::fromString(self::TENANT_ID),
            roles: $roles,
        );

        $client->loginUser($user, 'api');

        return $client;
    }

    private function persistSoftRulesWithMinimumDelay(int $days): void
    {
        /** @var Connection $connection */
        $connection = static::getContainer()->get(Connection::class);
        $rulesJson = json_encode([['type' => 'minimum_delay', 'params' => ['days' => $days]]], JSON_THROW_ON_ERROR);
        $connection->executeStatement(
            "INSERT INTO homework_rules (id, tenant_id, rules, enforcement_mode, enabled, created_at, updated_at)
             VALUES (gen_random_uuid(), :tid, :rules::jsonb, 'soft', true, NOW(), NOW())
             ON CONFLICT (tenant_id) DO UPDATE SET rules = :rules::jsonb, enforcement_mode = 'soft', enabled = true, updated_at = NOW()",
            ['tid' => self::TENANT_ID, 'rules' => $rulesJson],
        );
    }

    private function persistHardRulesWithMinimumDelay(int $days): void
    {
        /** @var Connection $connection */
        $connection = static::getContainer()->get(Connection::class);
        $rulesJson = json_encode([['type' => 'minimum_delay', 'params' => ['days' => $days]]], JSON_THROW_ON_ERROR);
        $connection->executeStatement(
            "INSERT INTO homework_rules (id, tenant_id, rules, enforcement_mode, enabled, created_at, updated_at)
             VALUES (gen_random_uuid(), :tid, :rules::jsonb, 'hard', true, NOW(), NOW())
             ON CONFLICT (tenant_id) DO UPDATE SET rules = :rules::jsonb, enforcement_mode = 'hard', enabled = true, updated_at = NOW()",
            ['tid' => self::TENANT_ID, 'rules' => $rulesJson],
        );
    }

    private function seedTeacherAssignment(): void
    {
        /** @var Connection $connection */
        $connection = static::getContainer()->get(Connection::class);

        // Compute the current academic year UUID the same way CurrentAcademicYearResolver does
        $month = (int) date('n');
        $year = (int) date('Y');
        $startYear = $month >= 9 ? $year : $year - 1;
        $academicYearId = Uuid::uuid5(
            '6ba7b814-9dad-11d1-80b4-00c04fd430c8',
            self::TENANT_ID . ':' . $startYear . '-' . ($startYear + 1),
        )->toString();

        $connection->executeStatement(
            "INSERT INTO teacher_assignments (id, tenant_id, teacher_id, school_class_id, subject_id, academic_year_id, status, start_date, created_at, updated_at)
             VALUES (gen_random_uuid(), :tid, :teacher, :class, :subject, :ayid, 'active', NOW(), NOW(), NOW())
             ON CONFLICT DO NOTHING",
            [
                'tid' => self::TENANT_ID,
                'teacher' => self::OWNER_TEACHER_ID,
                'class' => self::CLASS_ID,
                'subject' => self::SUBJECT_ID,
                'ayid' => $academicYearId,
            ],
        );
    }

    private function persistHomeworkWithRuleOverride(string $homeworkId): void
    {
        $now = new DateTimeImmutable();

        $homework = Homework::reconstitute(
            id: HomeworkId::fromString($homeworkId),
            tenantId: TenantId::fromString(self::TENANT_ID),
            classId: ClassId::fromString(self::CLASS_ID),
            subjectId: SubjectId::fromString(self::SUBJECT_ID),
            teacherId: UserId::fromString(self::OWNER_TEACHER_ID),
            title: 'Devoir existant',
            description: null,
            dueDate: new DateTimeImmutable('2026-06-15'),
            status: HomeworkStatus::PUBLISHED,
            createdAt: $now,
            updatedAt: $now,
            ruleOverride: ['warnings' => ['minimum_delay'], 'acknowledgedAt' => '2026-03-18T10:00:00+00:00'],
        );

        /** @var HomeworkRepository $repository */
        $repository = static::getContainer()->get(HomeworkRepository::class);
        $repository->save($homework);
    }

    private function persistHomework(string $homeworkId, HomeworkStatus $status): void
    {
        $now = new DateTimeImmutable();

        $homework = Homework::reconstitute(
            id: HomeworkId::fromString($homeworkId),
            tenantId: TenantId::fromString(self::TENANT_ID),
            classId: ClassId::fromString(self::CLASS_ID),
            subjectId: SubjectId::fromString(self::SUBJECT_ID),
            teacherId: UserId::fromString(self::OWNER_TEACHER_ID),
            title: 'Devoir existant',
            description: null,
            dueDate: new DateTimeImmutable('2026-06-15'),
            status: $status,
            createdAt: $now,
            updatedAt: $now,
        );

        /** @var HomeworkRepository $repository */
        $repository = static::getContainer()->get(HomeworkRepository::class);
        $repository->save($homework);
    }
}
