<?php

declare(strict_types=1);

use App\Domain\SmartLink\Entities\SmartLink;
use App\Domain\SmartLink\Enums\LinkStatus;
use App\Domain\SmartLink\Enums\LinkType;
use App\Domain\SmartLink\ValueObjects\LinkTitle;
use App\Domain\SmartLink\ValueObjects\ShortCode;
use App\Framework\DateTime\SystemClock;

describe('SmartLink Entity', function () {
    beforeEach(function () {
        $this->clock = new SystemClock();
        $this->shortCode = ShortCode::fromString('abc123');
        $this->title = LinkTitle::fromString('My Smart Link');
    });

    describe('creation', function () {
        it('creates smart link with required fields', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            expect($link->shortCode->toString())->toBe('abc123');
            expect($link->type)->toBe(LinkType::RELEASE);
            expect($link->title->toString())->toBe('My Smart Link');
            expect($link->status)->toBe(LinkStatus::DRAFT);
            expect($link->userId)->toBeNull();
            expect($link->coverImageUrl)->toBeNull();
        });

        it('creates smart link with user ID', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title,
                userId: 'user123'
            );

            expect($link->userId)->toBe('user123');
            expect($link->isOwnedBy('user123'))->toBeTrue();
        });

        it('creates smart link with cover image', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title,
                coverImageUrl: 'https://example.com/cover.jpg'
            );

            expect($link->coverImageUrl)->toBe('https://example.com/cover.jpg');
        });

        it('starts in DRAFT status', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            expect($link->status)->toBe(LinkStatus::DRAFT);
            expect($link->isActive())->toBeFalse();
        });
    });

    describe('status transitions', function () {
        it('transitions from DRAFT to ACTIVE', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            $activeLink = $link->withStatus(LinkStatus::ACTIVE);

            expect($activeLink->status)->toBe(LinkStatus::ACTIVE);
            expect($activeLink->isActive())->toBeTrue();
        });

        it('transitions from ACTIVE to PAUSED', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            )->withStatus(LinkStatus::ACTIVE);

            $pausedLink = $link->withStatus(LinkStatus::PAUSED);

            expect($pausedLink->status)->toBe(LinkStatus::PAUSED);
        });

        it('throws exception for invalid transition', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            // Cannot transition directly from DRAFT to PAUSED
            expect(fn() => $link->withStatus(LinkStatus::PAUSED))
                ->toThrow(\DomainException::class);
        });

        it('throws exception for invalid transition from EXPIRED', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            )->withStatus(LinkStatus::ACTIVE)->withStatus(LinkStatus::EXPIRED);

            // Cannot transition from EXPIRED to ACTIVE
            expect(fn() => $link->withStatus(LinkStatus::ACTIVE))
                ->toThrow(\DomainException::class);
        });
    });

    describe('title updates', function () {
        it('updates title', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            $newTitle = LinkTitle::fromString('Updated Title');
            $updatedLink = $link->withTitle($newTitle);

            expect($updatedLink->title->toString())->toBe('Updated Title');
            expect($link->title->toString())->toBe('My Smart Link'); // Original unchanged
        });
    });

    describe('access control', function () {
        it('identifies active links as active', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            )->withStatus(LinkStatus::ACTIVE);

            expect($link->isActive())->toBeTrue();
            expect($link->canBeAccessed())->toBeTrue();
        });

        it('identifies draft links as not accessible', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            expect($link->canBeAccessed())->toBeFalse();
        });

        it('identifies paused links as not accessible', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            )->withStatus(LinkStatus::ACTIVE)->withStatus(LinkStatus::PAUSED);

            expect($link->canBeAccessed())->toBeFalse();
        });
    });

    describe('ownership', function () {
        it('identifies owner correctly', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title,
                userId: 'user123'
            );

            expect($link->isOwnedBy('user123'))->toBeTrue();
            expect($link->isOwnedBy('user456'))->toBeFalse();
            expect($link->isOwnedBy(null))->toBeFalse();
        });

        it('handles anonymous links', function () {
            $link = SmartLink::create(
                clock: $this->clock,
                shortCode: $this->shortCode,
                type: LinkType::RELEASE,
                title: $this->title
            );

            expect($link->userId)->toBeNull();
            expect($link->isOwnedBy('user123'))->toBeFalse();
        });
    });
});
