<?php

declare(strict_types=1);

use App\Framework\Deployment\Ssl\ValueObjects\DomainName;

describe('DomainName', function () {
    it('creates domain name from valid string', function () {
        $domain = DomainName::fromString('example.com');

        expect($domain->value)->toBe('example.com');
    });

    it('accepts valid domain formats', function () {
        $validDomains = [
            'example.com',
            'subdomain.example.com',
            'sub.domain.example.com',
            'example-site.com',
            'example123.com',
            '123example.com',  // Starting with number in label is OK if not first character
            'a.com',
            'very-long-subdomain-name.example.com',
        ];

        foreach ($validDomains as $domainStr) {
            expect(fn() => DomainName::fromString($domainStr))
                ->not->toThrow(InvalidArgumentException::class);
        }
    });

    it('rejects invalid domain formats', function () {
        expect(fn() => DomainName::fromString(''))
            ->toThrow(InvalidArgumentException::class, 'Domain name cannot be empty');
    });

    it('rejects domain starting with hyphen', function () {
        expect(fn() => DomainName::fromString('-example.com'))
            ->toThrow(InvalidArgumentException::class);
    });

    it('rejects domain with invalid characters', function () {
        expect(fn() => DomainName::fromString('example$.com'))
            ->toThrow(InvalidArgumentException::class, 'Domain contains invalid characters');
    });

    it('rejects domain exceeding maximum length', function () {
        $longDomain = str_repeat('a', 254) . '.com';

        expect(fn() => DomainName::fromString($longDomain))
            ->toThrow(InvalidArgumentException::class, 'exceeds maximum length');
    });

    it('rejects label exceeding maximum length', function () {
        $longLabel = str_repeat('a', 64);

        expect(fn() => DomainName::fromString($longLabel . '.com'))
            ->toThrow(InvalidArgumentException::class, 'exceeds maximum length');
    });

    it('detects wildcard domains', function () {
        $wildcard = DomainName::fromString('*.example.com');

        expect($wildcard->isWildcard())->toBeTrue();
    });

    it('detects non-wildcard domains', function () {
        $normal = DomainName::fromString('example.com');

        expect($normal->isWildcard())->toBeFalse();
    });

    it('extracts TLD correctly', function () {
        $domain = DomainName::fromString('subdomain.example.com');

        expect($domain->getTld())->toBe('com');
    });

    it('extracts subdomain correctly', function () {
        $domain = DomainName::fromString('sub.example.com');

        expect($domain->getSubdomain())->toBe('sub');
    });

    it('returns null for domain without subdomain', function () {
        $domain = DomainName::fromString('example.com');

        expect($domain->getSubdomain())->toBeNull();
    });

    it('returns labels array', function () {
        $domain = DomainName::fromString('sub.example.com');

        expect($domain->getLabels())->toBe(['sub', 'example', 'com']);
    });

    it('converts to string', function () {
        $domain = DomainName::fromString('example.com');

        expect($domain->toString())->toBe('example.com');
        expect((string) $domain)->toBe('example.com');
    });

    it('compares domains correctly', function () {
        $domain1 = DomainName::fromString('example.com');
        $domain2 = DomainName::fromString('example.com');
        $domain3 = DomainName::fromString('other.com');

        expect($domain1->equals($domain2))->toBeTrue();
        expect($domain1->equals($domain3))->toBeFalse();
    });

    it('compares domains case-insensitively', function () {
        $domain1 = DomainName::fromString('Example.COM');
        $domain2 = DomainName::fromString('example.com');

        expect($domain1->equals($domain2))->toBeTrue();
    });
});
