<?php

declare(strict_types=1);

namespace App\Shared\Domain\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Post;
use App\Shared\Infrastructure\ApiPlatform\State\UploadedDocumentProcessor;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Attribute\Groups;

/**
 * Reference technique d'un fichier televerse (infra generique Shared, ERP-154).
 *
 * Entite IMMUABLE : un document n'est jamais modifie apres creation (pas d'onglet
 * edition cote front). Elle ne porte donc QUE `created_at` / `created_by` — pas
 * la paire `updated_*` — et n'implemente volontairement pas Timestampable /
 * Blamable (qui imposeraient les 4 colonnes). `created_at` est rempli par le
 * FileUploader via l'horloge injectee ; `created_by` est positionne par le
 * processor depuis l'utilisateur authentifie (null hors HTTP).
 *
 * Pas de `#[Auditable]` : c'est un enregistrement d'infrastructure (et non un
 * agregat metier edite), sa tracabilite est portee par created_at / created_by.
 *
 * Operations API :
 *  - Post (/uploaded_documents, multipart) : `deserialize: false` — le binaire
 *    n'est pas deserialise dans l'entite, le UploadedDocumentProcessor lit le
 *    fichier de la requete, delegue au FileUploader (validation MIME server-side,
 *    bornage taille, checksum, ecriture disque) puis persiste. MIME hors
 *    whitelist -> 422.
 *  - Get (/uploaded_documents/{id}) : necessaire pour qu'API Platform genere
 *    l'IRI renvoyee par le Post. Protege par IS_AUTHENTICATED_FULLY uniquement
 *    (pas de RBAC ni de cloisonnement tenant ici) : cette ressource est une
 *    infra GENERIQUE qui ne porte aucune notion de proprietaire metier. Le
 *    cloisonnement d'acces (qui peut voir quel document) est volontairement
 *    delegue au module CONSOMMATEUR (ex: la Decharge M4), qui exposera le
 *    document via sa propre ressource cloisonnee plutot que via cet endpoint
 *    technique. Ne renvoie que des metadonnees (jamais le binaire).
 *
 * Pas de GetCollection exposee (non requise) — la regle de pagination ne
 * s'applique donc pas ici.
 */
#[ORM\Entity]
#[ORM\Table(name: 'uploaded_document')]
#[ApiResource(
    operations: [
        new Get(
            security: "is_granted('IS_AUTHENTICATED_FULLY')",
        ),
        new Post(
            // Entree multipart : le binaire arrive en multipart/form-data sous
            // le champ « file ». Sans cet inputFormats, API Platform rejette la
            // requete en 415.
            inputFormats: ['multipart' => ['multipart/form-data']],
            // Le fichier n'est pas deserialisable dans l'entite : le processor
            // lit le binaire de la requete. La validation est portee par le
            // FileUploader (MIME server-side, taille), pas par les contraintes.
            deserialize: false,
            validate: false,
            security: "is_granted('IS_AUTHENTICATED_FULLY')",
            processor: UploadedDocumentProcessor::class,
        ),
    ],
    normalizationContext: ['groups' => ['uploaded_document:read']],
)]
class UploadedDocument
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    #[Groups(['uploaded_document:read'])]
    private ?int $id = null;

    #[ORM\Column(name: 'original_filename', length: 255)]
    #[Groups(['uploaded_document:read'])]
    private string $originalFilename;

    #[ORM\Column(name: 'stored_path', length: 512)]
    #[Groups(['uploaded_document:read'])]
    private string $storedPath;

    #[ORM\Column(name: 'mime_type', length: 100)]
    #[Groups(['uploaded_document:read'])]
    private string $mimeType;

    #[ORM\Column(name: 'size_bytes', type: 'integer')]
    #[Groups(['uploaded_document:read'])]
    private int $sizeBytes;

    #[ORM\Column(name: 'checksum', length: 64)]
    #[Groups(['uploaded_document:read'])]
    private string $checksum;

    #[ORM\Column(name: 'created_at', type: 'datetime_immutable')]
    #[Groups(['uploaded_document:read'])]
    private DateTimeImmutable $createdAt;

    #[ORM\ManyToOne(targetEntity: UserInterface::class)]
    #[ORM\JoinColumn(name: 'created_by', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?UserInterface $createdBy = null;

    public function __construct(
        string $originalFilename,
        string $storedPath,
        string $mimeType,
        int $sizeBytes,
        string $checksum,
        DateTimeImmutable $createdAt,
    ) {
        $this->originalFilename = $originalFilename;
        $this->storedPath       = $storedPath;
        $this->mimeType         = $mimeType;
        $this->sizeBytes        = $sizeBytes;
        $this->checksum         = $checksum;
        $this->createdAt        = $createdAt;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getOriginalFilename(): string
    {
        return $this->originalFilename;
    }

    public function getStoredPath(): string
    {
        return $this->storedPath;
    }

    public function getMimeType(): string
    {
        return $this->mimeType;
    }

    public function getSizeBytes(): int
    {
        return $this->sizeBytes;
    }

    public function getChecksum(): string
    {
        return $this->checksum;
    }

    public function getCreatedAt(): DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function getCreatedBy(): ?UserInterface
    {
        return $this->createdBy;
    }

    public function setCreatedBy(?UserInterface $user): void
    {
        $this->createdBy = $user;
    }
}
