<?php

declare(strict_types=1);

namespace App\Domain\Media;

use App\Framework\Core\ValueObjects\Dimensions;
use App\Framework\Core\ValueObjects\FileSize;
use App\Framework\Core\ValueObjects\Hash;
use App\Framework\Database\Attributes\Column;
use App\Framework\Database\Attributes\Entity;
use App\Framework\Database\Attributes\Type;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Http\MimeType;
use App\Framework\Ulid\Ulid;

#[Entity(tableName: 'images', idColumn: 'ulid')]
final readonly class Image
{
    /** @var ImageVariant[] $variants */
    #[Type(ImageVariant::class, foreignKey: 'image_id', localKey: 'ulid')]
    public array $variants;

    public function __construct(
        #[Column(name: 'ulid', primary: true)]
        public Ulid $ulid,
        #[Column(name: 'filename')]
        public string $filename,
        #[Column(name: 'original_filename')]
        public string $originalFilename,
        #[Column(name: 'mime_type')]
        public MimeType $mimeType,
        #[Column(name: 'file_size')]
        public FileSize $fileSize,
        #[Column(name: 'width')]
        public int $width,
        #[Column(name: 'height')]
        public int $height,
        #[Column(name: 'hash'/*, unique: true*/)]
        public Hash $hash,
        #[Column(name: 'path')]
        public FilePath $path,
        #[Column(name: 'alt_text')]
        public string $altText,
    ) {
    }

    /**
     * Get dimensions as Value Object
     */
    public function getDimensions(): Dimensions
    {
        return new Dimensions($this->width, $this->height);
    }

    /**
     * Get aspect ratio
     */
    public function getAspectRatio(): float
    {
        return $this->getDimensions()->getAspectRatio();
    }

    /**
     * Check if image is portrait orientation
     */
    public function isPortrait(): bool
    {
        return $this->getDimensions()->isPortrait();
    }

    /**
     * Check if image is landscape orientation
     */
    public function isLandscape(): bool
    {
        return $this->getDimensions()->isLandscape();
    }

    /**
     * Check if image is square
     */
    public function isSquare(): bool
    {
        return $this->getDimensions()->isSquare();
    }

    /**
     * Get human readable file size
     */
    public function getHumanReadableFileSize(): string
    {
        return $this->fileSize->toHumanReadable();
    }

    /**
     * Get file extension
     */
    public function getFileExtension(): string
    {
        return $this->path->getExtension();
    }

    /**
     * Check if hash matches
     */
    public function verifyHash(Hash $hash): bool
    {
        return $this->hash->equals($hash);
    }

    /**
     * Check if file is an image based on MIME type
     */
    public function isImageFile(): bool
    {
        return $this->mimeType->isImage();
    }

    /**
     * Get ULID as string
     */
    public function getUlidString(): string
    {
        return $this->ulid->__toString();
    }

    /**
     * Create new instance with updated filename
     */
    public function withFilename(string $filename): self
    {
        return new self(
            ulid: $this->ulid,
            filename: $filename,
            originalFilename: $this->originalFilename,
            mimeType: $this->mimeType,
            fileSize: $this->fileSize,
            width: $this->width,
            height: $this->height,
            hash: $this->hash,
            path: $this->path,
            altText: $this->altText
        );
    }

    /**
     * Create new instance with updated alt text
     */
    public function withAltText(string $altText): self
    {
        return new self(
            ulid: $this->ulid,
            filename: $this->filename,
            originalFilename: $this->originalFilename,
            mimeType: $this->mimeType,
            fileSize: $this->fileSize,
            width: $this->width,
            height: $this->height,
            hash: $this->hash,
            path: $this->path,
            altText: $altText
        );
    }

    /**
     * Create new instance with updated path
     */
    public function withPath(FilePath $path): self
    {
        return new self(
            ulid: $this->ulid,
            filename: $this->filename,
            originalFilename: $this->originalFilename,
            mimeType: $this->mimeType,
            fileSize: $this->fileSize,
            width: $this->width,
            height: $this->height,
            hash: $this->hash,
            path: $path,
            altText: $this->altText
        );
    }
}
