<?php

declare(strict_types=1);

namespace App\Framework\Http\Url;

/**
 * Smart URL factory with automatic spec selection
 *
 * Provides convenient factory methods that automatically select
 * the appropriate URL specification (RFC 3986 vs WHATWG) based
 * on the intended use case.
 *
 * Usage:
 * ```php
 * // API Client (RFC 3986)
 * $apiUrl = UrlFactory::forApiClient('https://api.example.com/users');
 *
 * // Browser Redirect (WHATWG)
 * $redirect = UrlFactory::forBrowserRedirect('https://example.com/dashboard');
 *
 * // Automatic selection
 * $url = UrlFactory::forUseCase(UrlUseCase::DEEP_LINK, 'myapp://open');
 * ```
 */
final readonly class UrlFactory
{
    /**
     * Parse URL with automatic spec detection
     *
     * Attempts to select appropriate spec based on scheme and structure.
     * Defaults to RFC 3986 for ambiguous cases.
     *
     * @param string $input URL string to parse
     * @param Url|null $base Optional base URL
     * @return Url Parsed URL with selected spec
     */
    public static function parse(string $input, ?Url $base = null): Url
    {
        // Heuristic: Use WHATWG for http/https URLs, RFC 3986 for others
        $scheme = parse_url($input, PHP_URL_SCHEME);

        if (in_array($scheme, ['http', 'https', 'file', 'ws', 'wss'], true)) {
            return WhatwgUrl::parse($input, $base);
        }

        return Rfc3986Url::parse($input, $base);
    }

    /**
     * Parse URL for specific use case with automatic spec selection
     *
     * @param UrlUseCase $useCase Intended use case
     * @param string $input URL string to parse
     * @param Url|null $base Optional base URL
     * @return Url Parsed URL with spec matching use case
     */
    public static function forUseCase(UrlUseCase $useCase, string $input, ?Url $base = null): Url
    {
        $spec = UrlSpec::forUseCase($useCase);

        return match ($spec) {
            UrlSpec::RFC3986 => Rfc3986Url::parse($input, $base),
            UrlSpec::WHATWG => WhatwgUrl::parse($input, $base),
        };
    }

    /**
     * Create URL for API client use (RFC 3986)
     *
     * Best for:
     * - REST API calls
     * - GraphQL endpoints
     * - SOAP services
     * - Webhook URLs
     *
     * @param string $input API endpoint URL
     * @param Url|null $base Optional base URL
     * @return Rfc3986Url RFC 3986 compliant URL
     */
    public static function forApiClient(string $input, ?Url $base = null): Rfc3986Url
    {
        return Rfc3986Url::parse($input, $base);
    }

    /**
     * Create URL for cURL request (RFC 3986)
     *
     * Best for:
     * - cURL operations
     * - HTTP client requests
     * - File transfers
     *
     * @param string $input Request URL
     * @param Url|null $base Optional base URL
     * @return Rfc3986Url RFC 3986 compliant URL
     */
    public static function forCurlRequest(string $input, ?Url $base = null): Rfc3986Url
    {
        return Rfc3986Url::parse($input, $base);
    }

    /**
     * Create URL for signature generation (RFC 3986)
     *
     * Best for:
     * - OAuth signatures
     * - AWS request signing
     * - HMAC-based authentication
     * - Webhook signature verification
     *
     * @param string $input URL to sign
     * @param Url|null $base Optional base URL
     * @return Rfc3986Url RFC 3986 compliant URL
     */
    public static function forSignature(string $input, ?Url $base = null): Rfc3986Url
    {
        return Rfc3986Url::parse($input, $base);
    }

    /**
     * Create canonical URL (RFC 3986)
     *
     * Best for:
     * - SEO canonical URLs
     * - Duplicate content detection
     * - URL normalization
     * - Sitemap generation
     *
     * @param string $input URL to canonicalize
     * @param Url|null $base Optional base URL
     * @return Rfc3986Url RFC 3986 compliant URL
     */
    public static function forCanonical(string $input, ?Url $base = null): Rfc3986Url
    {
        return Rfc3986Url::parse($input, $base);
    }

    /**
     * Create URL for browser redirect (WHATWG)
     *
     * Best for:
     * - HTTP redirects (302, 301, etc.)
     * - Location headers
     * - User-facing redirects
     *
     * @param string $input Redirect target URL
     * @param Url|null $base Optional base URL
     * @return WhatwgUrl WHATWG compliant URL
     */
    public static function forBrowserRedirect(string $input, ?Url $base = null): WhatwgUrl
    {
        return WhatwgUrl::parse($input, $base);
    }

    /**
     * Create URL for deep link (WHATWG)
     *
     * Best for:
     * - Universal links
     * - App deep links
     * - Mobile-to-web links
     * - Cross-platform navigation
     *
     * @param string $input Deep link URL
     * @param Url|null $base Optional base URL
     * @return WhatwgUrl WHATWG compliant URL
     */
    public static function forDeepLink(string $input, ?Url $base = null): WhatwgUrl
    {
        return WhatwgUrl::parse($input, $base);
    }

    /**
     * Create URL for HTML form action (WHATWG)
     *
     * Best for:
     * - Form submission targets
     * - HTML5 form actions
     * - Browser form handling
     *
     * @param string $input Form action URL
     * @param Url|null $base Optional base URL
     * @return WhatwgUrl WHATWG compliant URL
     */
    public static function forFormAction(string $input, ?Url $base = null): WhatwgUrl
    {
        return WhatwgUrl::parse($input, $base);
    }

    /**
     * Create URL for client-side JavaScript (WHATWG)
     *
     * Best for:
     * - JavaScript fetch() API
     * - XMLHttpRequest URLs
     * - Browser URL API compatibility
     * - Client-side routing
     *
     * @param string $input JavaScript URL
     * @param Url|null $base Optional base URL
     * @return WhatwgUrl WHATWG compliant URL
     */
    public static function forClientSide(string $input, ?Url $base = null): WhatwgUrl
    {
        return WhatwgUrl::parse($input, $base);
    }

    /**
     * Convert between URL specs
     *
     * @param Url $url URL to convert
     * @param UrlSpec $targetSpec Target specification
     * @return Url Converted URL
     */
    public static function convert(Url $url, UrlSpec $targetSpec): Url
    {
        if ($url->getSpec() === $targetSpec) {
            return $url;
        }

        $urlString = $url->toString();

        return match ($targetSpec) {
            UrlSpec::RFC3986 => Rfc3986Url::parse($urlString),
            UrlSpec::WHATWG => WhatwgUrl::parse($urlString),
        };
    }
}
