<?php

declare(strict_types=1);

namespace App\Tests\Unit\Scolarite\Application\Command\UploadSubmissionAttachment;

use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Application\Command\UploadSubmissionAttachment\UploadSubmissionAttachmentCommand;
use App\Scolarite\Application\Command\UploadSubmissionAttachment\UploadSubmissionAttachmentHandler;
use App\Scolarite\Application\Port\FileStorage;
use App\Scolarite\Domain\Exception\RenduDejaSoumisException;
use App\Scolarite\Domain\Model\Homework\HomeworkId;
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmission;
use App\Scolarite\Infrastructure\Persistence\InMemory\InMemoryHomeworkSubmissionRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class UploadSubmissionAttachmentHandlerTest extends TestCase
{
    private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
    private const string HOMEWORK_ID = '550e8400-e29b-41d4-a716-446655440050';
    private const string STUDENT_ID = '550e8400-e29b-41d4-a716-446655440060';

    private InMemoryHomeworkSubmissionRepository $submissionRepository;
    private string $tempFile;

    protected function setUp(): void
    {
        $this->submissionRepository = new InMemoryHomeworkSubmissionRepository();
        $this->tempFile = tempnam(sys_get_temp_dir(), 'e2e_upload_');
        file_put_contents($this->tempFile, 'fake PDF content');
    }

    protected function tearDown(): void
    {
        if (file_exists($this->tempFile)) {
            unlink($this->tempFile);
        }
    }

    #[Test]
    public function itUploadsAttachmentForDraftSubmission(): void
    {
        $submission = $this->createDraftSubmission();
        $this->submissionRepository->save($submission);

        $handler = $this->createHandler();
        $command = new UploadSubmissionAttachmentCommand(
            tenantId: self::TENANT_ID,
            submissionId: (string) $submission->id,
            filename: 'devoir.pdf',
            mimeType: 'application/pdf',
            fileSize: 1024,
            tempFilePath: $this->tempFile,
        );

        $attachment = $handler($command);

        self::assertSame('devoir.pdf', $attachment->filename);
        self::assertSame('application/pdf', $attachment->mimeType);
        self::assertSame(1024, $attachment->fileSize);
        self::assertStringContainsString('submissions/', $attachment->filePath);
    }

    #[Test]
    public function itRejectsUploadOnSubmittedSubmission(): void
    {
        $submission = $this->createDraftSubmission();
        $submission->soumettre(
            dueDate: new DateTimeImmutable('2026-04-15'),
            now: new DateTimeImmutable('2026-03-24 11:00:00'),
        );
        $this->submissionRepository->save($submission);

        $handler = $this->createHandler();
        $command = new UploadSubmissionAttachmentCommand(
            tenantId: self::TENANT_ID,
            submissionId: (string) $submission->id,
            filename: 'devoir.pdf',
            mimeType: 'application/pdf',
            fileSize: 1024,
            tempFilePath: $this->tempFile,
        );

        $this->expectException(RenduDejaSoumisException::class);

        $handler($command);
    }

    private function createDraftSubmission(): HomeworkSubmission
    {
        return HomeworkSubmission::creerBrouillon(
            tenantId: TenantId::fromString(self::TENANT_ID),
            homeworkId: HomeworkId::fromString(self::HOMEWORK_ID),
            studentId: UserId::fromString(self::STUDENT_ID),
            responseHtml: '<p>Ma réponse</p>',
            now: new DateTimeImmutable('2026-03-24 10:00:00'),
        );
    }

    private function createHandler(): UploadSubmissionAttachmentHandler
    {
        $fileStorage = new class implements FileStorage {
            public function upload(string $path, mixed $content, string $mimeType): string
            {
                return $path;
            }

            public function delete(string $path): void
            {
            }
        };

        $clock = new class implements Clock {
            public function now(): DateTimeImmutable
            {
                return new DateTimeImmutable('2026-03-24 10:00:00');
            }
        };

        return new UploadSubmissionAttachmentHandler(
            $this->submissionRepository,
            $fileStorage,
            $clock,
        );
    }
}
