<?php

declare(strict_types=1);

use App\Framework\Router\ValueObjects\Placeholder;
use App\Framework\Router\ValueObjects\RoutePath;

describe('RoutePath', function () {
    describe('creation', function () {
        it('can be created from elements', function () {
            $path = RoutePath::fromElements('api', 'users', Placeholder::fromString('id'));

            expect($path->toString())->toBe('/api/users/{id}');
            expect($path->isDynamic())->toBeTrue();
            expect($path->getParameterNames())->toBe(['id']);
        });

        it('can be created from string', function () {
            $path = RoutePath::fromString('/api/users/{id}');

            expect($path->toString())->toBe('/api/users/{id}');
            expect($path->isDynamic())->toBeTrue();
            expect($path->getParameterNames())->toBe(['id']);
        });

        it('handles static routes', function () {
            $path = RoutePath::fromElements('api', 'health');

            expect($path->toString())->toBe('/api/health');
            expect($path->isStatic())->toBeTrue();
            expect($path->getParameterNames())->toBe([]);
        });

        it('handles wildcard parameters', function () {
            $path = RoutePath::fromString('/files/{path*}');

            expect($path->toString())->toBe('/files/{path*}');

            $placeholders = $path->getPlaceholders();
            expect($placeholders)->toHaveCount(1);
            expect($placeholders[0]->isWildcard())->toBeTrue();
        });

        it('throws on empty path', function () {
            expect(fn () => RoutePath::fromElements())
                ->toThrow(InvalidArgumentException::class);
        });
    });

    describe('fluent builder', function () {
        it('can build paths fluently', function () {
            $path = RoutePath::create()
                ->segment('api')
                ->segment('users')
                ->parameter('id')
                ->build();

            expect($path->toString())->toBe('/api/users/{id}');
        });

        it('supports typed parameters', function () {
            $path = RoutePath::create()
                ->segment('api')
                ->segment('users')
                ->typedParameter('id', 'uuid')
                ->build();

            $placeholders = $path->getPlaceholders();
            expect($placeholders[0]->getType())->toBe('uuid');
        });

        it('supports quick patterns', function () {
            $path = RoutePath::create()
                ->segment('api')
                ->segment('users')
                ->uuid();

            expect($path->toString())->toBe('/api/users/{id}');
        });
    });

    describe('regex compilation', function () {
        it('compiles static routes to regex', function () {
            $path = RoutePath::fromString('/api/health');

            expect($path->toRegex())->toBe('~^/api/health$~');
        });

        it('compiles dynamic routes to regex', function () {
            $path = RoutePath::fromString('/api/users/{id}');

            expect($path->toRegex())->toBe('~^/api/users/([^/]+)$~');
        });

        it('compiles typed parameters correctly', function () {
            $path = RoutePath::fromElements(
                'api',
                'users',
                Placeholder::typed('id', 'int')
            );

            expect($path->toRegex())->toBe('~^/api/users/(\d+)$~');
        });

        it('compiles wildcard parameters', function () {
            $path = RoutePath::fromElements(
                'files',
                Placeholder::wildcard('path')
            );

            expect($path->toRegex())->toBe('~^/files/(.+?)$~');
        });
    });

    describe('manipulation', function () {
        it('can append elements', function () {
            $base = RoutePath::fromElements('api', 'users');
            $extended = $base->append(Placeholder::fromString('id'));

            expect($extended->toString())->toBe('/api/users/{id}');
        });

        it('can prepend elements', function () {
            $base = RoutePath::fromElements('users', Placeholder::fromString('id'));
            $extended = $base->prepend('api');

            expect($extended->toString())->toBe('/api/users/{id}');
        });
    });

    describe('analysis', function () {
        it('counts segments correctly', function () {
            $path = RoutePath::fromString('/api/users/{id}');

            expect($path->getSegmentCount())->toBe(3);
        });

        it('identifies placeholders', function () {
            $path = RoutePath::fromString('/api/users/{id}/posts/{postId}');

            $placeholders = $path->getPlaceholders();
            expect($placeholders)->toHaveCount(2);
            expect($path->getParameterNames())->toBe(['id', 'postId']);
        });
    });

    describe('validation', function () {
        it('validates segment content', function () {
            expect(fn () => RoutePath::fromElements('api', ''))
                ->toThrow(InvalidArgumentException::class);
        });

        it('rejects invalid characters in segments', function () {
            expect(fn () => RoutePath::fromElements('api', 'users{id}'))
                ->toThrow(InvalidArgumentException::class);
        });
    });
});
