<?php

declare(strict_types=1);

use App\Domain\Media\Image;
use App\Framework\Core\ValueObjects\FileSize;
use App\Framework\Core\ValueObjects\Hash;
use App\Framework\DateTime\SystemClock;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Http\MimeType;
use App\Framework\Ulid\Ulid;

beforeEach(function () {
    // Create test directory structure
    $this->testDir = '/tmp/test_images';
    if (! is_dir($this->testDir)) {
        mkdir($this->testDir, 0755, true);
    }

    // Create test image file
    $this->testImagePath = $this->testDir . '/test.jpg';
    file_put_contents($this->testImagePath, 'fake-image-content');

    // Create Clock instance
    $clock = new SystemClock();

    $this->testImage = new Image(
        ulid: Ulid::fromString($clock, '00MF9VW9R36NJN3VCFSTS2CK6R'),
        filename: 'test.jpg',
        originalFilename: 'original-test.jpg',
        mimeType: MimeType::fromString('image/jpeg'),
        fileSize: FileSize::fromBytes(strlen('fake-image-content')),
        width: 100,
        height: 200,
        hash: Hash::fromString('2f36ee4cde5b43e02c118f4b21e5a4904d0c13597b5c2f1127097b808080622d'),
        path: FilePath::create($this->testDir),
        altText: 'Test image'
    );
});

afterEach(function () {
    // Clean up test files
    if (file_exists($this->testImagePath)) {
        unlink($this->testImagePath);
    }
    if (is_dir($this->testDir)) {
        rmdir($this->testDir);
    }
});

it('can create Image entity with Value Objects', function () {
    expect($this->testImage->filename)->toBe('test.jpg');
    expect($this->testImage->originalFilename)->toBe('original-test.jpg');
    expect($this->testImage->width)->toBe(100);
    expect($this->testImage->height)->toBe(200);
    expect($this->testImage->altText)->toBe('Test image');
});

it('can get full file path using FilePath join', function () {
    $fullPath = $this->testImage->path->join($this->testImage->filename);
    expect($fullPath->toString())->toBe($this->testDir . '/test.jpg');
});

it('can check if image file exists on filesystem', function () {
    $fullPath = $this->testImage->path->join($this->testImage->filename);
    expect(file_exists($fullPath->toString()))->toBeTrue();
});

it('returns correct MIME type', function () {
    expect($this->testImage->mimeType->value)->toBe('image/jpeg');
    expect($this->testImage->mimeType->isImage())->toBeTrue();
});

it('can verify hash', function () {
    $testHash = Hash::fromString('2f36ee4cde5b43e02c118f4b21e5a4904d0c13597b5c2f1127097b808080622d');
    expect($this->testImage->verifyHash($testHash))->toBeTrue();

    $wrongHash = Hash::fromString('1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef');
    expect($this->testImage->verifyHash($wrongHash))->toBeFalse();
});

it('can get human readable file size', function () {
    $readableSize = $this->testImage->getHumanReadableFileSize();
    expect($readableSize)->toBeString();
    expect(strlen($readableSize))->toBeGreaterThan(0);
});

it('can get image dimensions and aspect ratio', function () {
    $dimensions = $this->testImage->getDimensions();
    expect($dimensions->width)->toBe(100);
    expect($dimensions->height)->toBe(200);

    $aspectRatio = $this->testImage->getAspectRatio();
    expect($aspectRatio)->toBe(0.5); // 100/200

    expect($this->testImage->isPortrait())->toBeTrue();
    expect($this->testImage->isLandscape())->toBeFalse();
    expect($this->testImage->isSquare())->toBeFalse();
});

it('can create immutable copy with updated filename', function () {
    $newImage = $this->testImage->withFilename('new-name.jpg');

    expect($newImage->filename)->toBe('new-name.jpg');
    expect($this->testImage->filename)->toBe('test.jpg'); // Original unchanged
    expect($newImage->ulid)->toEqual($this->testImage->ulid); // Other properties same
});

it('can create immutable copy with updated alt text', function () {
    $newImage = $this->testImage->withAltText('Updated alt text');

    expect($newImage->altText)->toBe('Updated alt text');
    expect($this->testImage->altText)->toBe('Test image'); // Original unchanged
});

it('can create immutable copy with updated path', function () {
    $newPath = FilePath::create('/new/path');
    $newImage = $this->testImage->withPath($newPath);

    expect($newImage->path->toString())->toBe('/new/path');
    expect($this->testImage->path->toString())->toBe($this->testDir); // Original unchanged
});
