<?php

declare(strict_types=1);

use App\Domain\Common\ValueObject\PhoneNumber;

describe('PhoneNumber Value Object', function () {
    it('creates phone number from valid string', function () {
        $phone = PhoneNumber::from('+49 123 456789');
        expect($phone->getValue())->toBe('+49 123 456789');
    });

    it('creates phone number with parse method', function () {
        $phone = PhoneNumber::parse('+49-123-456-789');
        expect($phone->getValue())->toBe('+49 123 456 789');
    });

    it('throws exception for empty phone number', function () {
        expect(fn () => PhoneNumber::from(''))
            ->toThrow(InvalidArgumentException::class, 'Phone number cannot be empty.');
    });

    it('throws exception for phone number without digits', function () {
        expect(fn () => PhoneNumber::from('abc'))
            ->toThrow(InvalidArgumentException::class, 'Phone number must contain digits: abc');
    });

    it('throws exception for too short phone number', function () {
        expect(fn () => PhoneNumber::from('123'))
            ->toThrow(InvalidArgumentException::class, 'Phone number too short: 123');
    });

    it('throws exception for too long phone number', function () {
        expect(fn () => PhoneNumber::from('123456789012345678901'))
            ->toThrow(InvalidArgumentException::class, 'Phone number too long: 123456789012345678901');
    });

    it('throws exception for invalid format', function () {
        expect(fn () => PhoneNumber::from('+49#123#456'))
            ->toThrow(InvalidArgumentException::class, 'Invalid phone number format: +49#123#456');
    });

    it('validates phone numbers correctly', function () {
        expect(PhoneNumber::isValid('+49 123 456789'))->toBeTrue();
        expect(PhoneNumber::isValid('0123 456789'))->toBeTrue();
        expect(PhoneNumber::isValid('+1 (555) 123-4567'))->toBeTrue();
        expect(PhoneNumber::isValid(''))->toBeFalse();
        expect(PhoneNumber::isValid('abc'))->toBeFalse();
        expect(PhoneNumber::isValid('123'))->toBeFalse();
    });

    it('extracts country code correctly', function () {
        $phone1 = PhoneNumber::from('+49 123 456789');
        expect($phone1->getCountryCode())->toBe('49');

        $phone2 = PhoneNumber::from('+1 555 123 4567');
        expect($phone2->getCountryCode())->toBe('1');

        $phone3 = PhoneNumber::from('0123 456789');
        expect($phone3->getCountryCode())->toBeNull();
    });

    it('extracts national number correctly', function () {
        $phone1 = PhoneNumber::from('+49 123 456789');
        expect($phone1->getNationalNumber())->toBe(' 123 456789');

        $phone2 = PhoneNumber::from('0123 456789');
        expect($phone2->getNationalNumber())->toBe('0123 456789');
    });

    it('detects mobile numbers correctly', function () {
        // German mobile numbers
        $mobile1 = PhoneNumber::from('+49 15 12345678');
        expect($mobile1->isMobile())->toBeTrue();

        $mobile2 = PhoneNumber::from('+49 16 12345678');
        expect($mobile2->isMobile())->toBeTrue();

        $mobile3 = PhoneNumber::from('+49 17 12345678');
        expect($mobile3->isMobile())->toBeTrue();

        // German landline
        $landline = PhoneNumber::from('+49 30 12345678');
        expect($landline->isMobile())->toBeFalse();

        // US numbers (10 digits are considered mobile for demo)
        $usMobile = PhoneNumber::from('+1 555 123 4567');
        expect($usMobile->isMobile())->toBeTrue();

        // General heuristic: 10+ digits
        $longNumber = PhoneNumber::from('+999 1234567890');
        expect($longNumber->isMobile())->toBeTrue();
    });

    it('formats to E164 correctly', function () {
        $phone1 = PhoneNumber::from('+49 123 456 789');
        expect($phone1->toE164())->toBe('+49123456789');

        $phone2 = PhoneNumber::from('0123 456789');
        expect($phone2->toE164())->toBe('+49123456789'); // Assumes German for demo

        $phone3 = PhoneNumber::from('+1 (555) 123-4567');
        expect($phone3->toE164())->toBe('+15551234567');
    });

    it('formats to international display format', function () {
        $phone1 = PhoneNumber::from('+49 123456789');
        $international = $phone1->toInternational();
        expect($international)->toContain('+49');
        expect($international)->toContain('123');

        $phone2 = PhoneNumber::from('+1 5551234567');
        $international2 = $phone2->toInternational();
        expect($international2)->toContain('+1');
        expect($international2)->toContain('555');
    });

    it('formats to national display format', function () {
        $phone1 = PhoneNumber::from('+49 123456789');
        $national = $phone1->toNational();
        expect($national)->toContain('0'); // German national format starts with 0
        expect($national)->toContain('123');

        $phone2 = PhoneNumber::from('+1 5551234567');
        $national2 = $phone2->toNational();
        expect($national2)->toContain('(555)'); // US format with parentheses
    });

    it('compares phone numbers correctly', function () {
        $phone1 = PhoneNumber::from('+49 123 456789');
        $phone2 = PhoneNumber::from('+49-123-456-789');
        $phone3 = PhoneNumber::from('+1 555 123 4567');

        expect($phone1->equals($phone2))->toBeTrue(); // Same number, different formatting
        expect($phone1->equals($phone3))->toBeFalse(); // Different numbers
    });

    it('checks same country correctly', function () {
        $phone1 = PhoneNumber::from('+49 123 456789');
        $phone2 = PhoneNumber::from('+49 987 654321');
        $phone3 = PhoneNumber::from('+1 555 123 4567');

        expect($phone1->isSameCountry($phone2))->toBeTrue();
        expect($phone1->isSameCountry($phone3))->toBeFalse();
    });

    it('converts to string correctly', function () {
        $phone = PhoneNumber::from('+49 123 456789');
        expect((string)$phone)->toBe('+49 123 456789');
        expect($phone->__toString())->toBe('+49 123 456789');
    });

    it('handles various input formats', function () {
        $formats = [
            '+49 123 456789',
            '+49-123-456-789',
            '+49.123.456.789',
            '+49 (123) 456-789',
            '0049 123 456789',
            '0123 456789',
            '123456789',
        ];

        foreach ($formats as $format) {
            $phone = PhoneNumber::parse($format);
            expect($phone)->toBeInstanceOf(PhoneNumber::class);
            expect(strlen($phone->getValue()))->toBeGreaterThan(8);
        }
    });

    it('normalizes input correctly', function () {
        $phone1 = PhoneNumber::parse('+49--123..456((789))');
        expect($phone1->getValue())->toBe('+49 123 456 789');

        $phone2 = PhoneNumber::parse('  +49   123   456   789  ');
        expect($phone2->getValue())->toBe('+49 123 456 789');
    });
});
