<?php

declare(strict_types=1);

use App\Domain\Common\ValueObject\PhoneNumber;
use App\Framework\Database\TypeCaster\PhoneNumberCaster;

describe('PhoneNumberCaster', function () {
    beforeEach(function () {
        $this->caster = new PhoneNumberCaster();
    });

    it('supports PhoneNumber type', function () {
        expect($this->caster->supports(PhoneNumber::class))->toBeTrue();
        expect($this->caster->supports('string'))->toBeFalse();
        expect($this->caster->supports('SomeOtherClass'))->toBeFalse();
    });

    it('casts from database string to PhoneNumber', function () {
        $phoneString = '+49 123 456789';
        $result = $this->caster->fromDatabase($phoneString);

        expect($result)->toBeInstanceOf(PhoneNumber::class);
        expect($result->getValue())->toBe($phoneString);
    });

    it('casts null from database to null', function () {
        $result = $this->caster->fromDatabase(null);
        expect($result)->toBeNull();
    });

    it('casts empty string from database to null', function () {
        $result = $this->caster->fromDatabase('');
        expect($result)->toBeNull();
    });

    it('throws exception for non-string database value', function () {
        expect(fn () => $this->caster->fromDatabase(123))
            ->toThrow(InvalidArgumentException::class, 'Expected string for PhoneNumber, got integer');

        expect(fn () => $this->caster->fromDatabase([]))
            ->toThrow(InvalidArgumentException::class, 'Expected string for PhoneNumber, got array');
    });

    it('casts PhoneNumber to database string', function () {
        $phone = PhoneNumber::from('+49 123 456789');
        $result = $this->caster->toDatabase($phone);

        expect($result)->toBe('+49 123 456789');
    });

    it('casts null PhoneNumber to null', function () {
        $result = $this->caster->toDatabase(null);
        expect($result)->toBeNull();
    });

    it('throws exception for non-PhoneNumber value', function () {
        expect(fn () => $this->caster->toDatabase('string'))
            ->toThrow(InvalidArgumentException::class, 'Expected PhoneNumber instance, got string');

        expect(fn () => $this->caster->toDatabase(123))
            ->toThrow(InvalidArgumentException::class, 'Expected PhoneNumber instance, got integer');
    });

    it('handles round-trip conversion correctly', function () {
        $originalPhone = PhoneNumber::from('+49 151 12345678');

        // To database
        $dbValue = $this->caster->toDatabase($originalPhone);
        expect($dbValue)->toBe('+49 151 12345678');

        // From database
        $restoredPhone = $this->caster->fromDatabase($dbValue);
        expect($restoredPhone)->toBeInstanceOf(PhoneNumber::class);
        expect($restoredPhone->getValue())->toBe($originalPhone->getValue());
        expect($restoredPhone->equals($originalPhone))->toBeTrue();
    });

    it('preserves phone number formatting through database', function () {
        $testNumbers = [
            '+49 123 456789',
            '+1 (555) 123-4567',
            '0123 456789',
            '+33 1 23 45 67 89',
        ];

        foreach ($testNumbers as $number) {
            $phone = PhoneNumber::from($number);
            $dbValue = $this->caster->toDatabase($phone);
            $restoredPhone = $this->caster->fromDatabase($dbValue);

            expect($restoredPhone->getValue())->toBe($number);
        }
    });
});
