<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\Doctrine;

use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmissionId;
use App\Scolarite\Domain\Model\HomeworkSubmission\SubmissionAttachment;
use App\Scolarite\Domain\Model\HomeworkSubmission\SubmissionAttachmentId;
use App\Scolarite\Domain\Repository\SubmissionAttachmentRepository;

use function array_map;

use DateTimeImmutable;
use Doctrine\DBAL\Connection;
use Override;

final readonly class DoctrineSubmissionAttachmentRepository implements SubmissionAttachmentRepository
{
    public function __construct(
        private Connection $connection,
    ) {
    }

    #[Override]
    public function findBySubmissionId(HomeworkSubmissionId $submissionId): array
    {
        $rows = $this->connection->fetchAllAssociative(
            'SELECT * FROM submission_attachments WHERE submission_id = :submission_id',
            ['submission_id' => (string) $submissionId],
        );

        return array_map($this->hydrate(...), $rows);
    }

    #[Override]
    public function save(HomeworkSubmissionId $submissionId, SubmissionAttachment $attachment): void
    {
        $this->connection->executeStatement(
            'INSERT INTO submission_attachments (id, submission_id, filename, file_path, file_size, mime_type, uploaded_at)
             VALUES (:id, :submission_id, :filename, :file_path, :file_size, :mime_type, :uploaded_at)',
            [
                'id' => (string) $attachment->id,
                'submission_id' => (string) $submissionId,
                'filename' => $attachment->filename,
                'file_path' => $attachment->filePath,
                'file_size' => $attachment->fileSize,
                'mime_type' => $attachment->mimeType,
                'uploaded_at' => $attachment->uploadedAt->format(DateTimeImmutable::ATOM),
            ],
        );
    }

    #[Override]
    public function delete(HomeworkSubmissionId $submissionId, SubmissionAttachment $attachment): void
    {
        $this->connection->executeStatement(
            'DELETE FROM submission_attachments WHERE id = :id AND submission_id = :submission_id',
            [
                'id' => (string) $attachment->id,
                'submission_id' => (string) $submissionId,
            ],
        );
    }

    /** @param array<string, mixed> $row */
    private function hydrate(array $row): SubmissionAttachment
    {
        /** @var string $id */
        $id = $row['id'];
        /** @var string $filename */
        $filename = $row['filename'];
        /** @var string $filePath */
        $filePath = $row['file_path'];
        /** @var string|int $rawFileSize */
        $rawFileSize = $row['file_size'];
        $fileSize = (int) $rawFileSize;
        /** @var string $mimeType */
        $mimeType = $row['mime_type'];
        /** @var string $uploadedAt */
        $uploadedAt = $row['uploaded_at'];

        return new SubmissionAttachment(
            id: SubmissionAttachmentId::fromString($id),
            filename: $filename,
            filePath: $filePath,
            fileSize: $fileSize,
            mimeType: $mimeType,
            uploadedAt: new DateTimeImmutable($uploadedAt),
        );
    }
}
