<?php

declare(strict_types=1);

namespace App\Framework\Http\Url;

/**
 * Unified URL interface for native PHP 8.5 URL API
 *
 * Abstracts RFC 3986 and WHATWG URL implementations
 * providing a unified API surface for URL manipulation.
 *
 * Replaces old Uri class with full-featured URL handling.
 *
 * All implementations must be immutable - modification methods
 * return new instances (wither pattern).
 */
interface Url
{
    /**
     * Parse URL from string with optional base URL
     *
     * @param string $input URL string to parse
     * @param self|null $base Optional base URL for relative resolution
     * @return self New URL instance
     * @throws \InvalidArgumentException If URL is invalid
     */
    public static function parse(string $input, ?self $base = null): self;

    /**
     * Get URL specification this instance conforms to
     *
     * @return UrlSpec Either RFC3986 or WHATWG
     */
    public function getSpec(): UrlSpec;

    // Component Getters

    /**
     * Get URL scheme (e.g., 'https', 'ftp')
     *
     * @return string Scheme without trailing colon, empty string if absent
     */
    public function getScheme(): string;

    /**
     * Get host component (domain or IP address)
     *
     * @return string Host, empty string if absent
     */
    public function getHost(): string;

    /**
     * Get port number
     *
     * @return int|null Port number, null if default or absent
     */
    public function getPort(): ?int;

    /**
     * Get path component
     *
     * @return string Path, empty string if absent
     */
    public function getPath(): string;

    /**
     * Get query string
     *
     * @return string Query without leading '?', empty string if absent
     */
    public function getQuery(): string;

    /**
     * Get fragment identifier
     *
     * @return string Fragment without leading '#', empty string if absent
     */
    public function getFragment(): string;

    /**
     * Get user info (username:password)
     *
     * @return string User info, empty string if absent
     */
    public function getUserInfo(): string;

    // Immutable Withers (Framework Pattern)

    /**
     * Return instance with specified scheme
     *
     * @param string $scheme New scheme
     * @return self New instance with updated scheme
     */
    public function withScheme(string $scheme): self;

    /**
     * Return instance with specified host
     *
     * @param string $host New host
     * @return self New instance with updated host
     */
    public function withHost(string $host): self;

    /**
     * Return instance with specified port
     *
     * @param int|null $port New port, null for default
     * @return self New instance with updated port
     */
    public function withPort(?int $port): self;

    /**
     * Return instance with specified path
     *
     * @param string $path New path
     * @return self New instance with updated path
     */
    public function withPath(string $path): self;

    /**
     * Return instance with specified query
     *
     * @param string $query New query string (without leading '?')
     * @return self New instance with updated query
     */
    public function withQuery(string $query): self;

    /**
     * Return instance with specified fragment
     *
     * @param string $fragment New fragment (without leading '#')
     * @return self New instance with updated fragment
     */
    public function withFragment(string $fragment): self;

    /**
     * Return instance with specified user info
     *
     * @param string $user Username
     * @param string|null $password Optional password
     * @return self New instance with updated user info
     */
    public function withUserInfo(string $user, ?string $password = null): self;

    // Serialization

    /**
     * Convert URL to string representation
     *
     * @return string Complete URL string
     */
    public function toString(): string;

    /**
     * Convert URL to ASCII-compatible string (Punycode/IDNA)
     *
     * @return string ASCII-encoded URL for international domain names
     */
    public function toAsciiString(): string;

    // Utilities

    /**
     * Resolve relative URL against this URL as base
     *
     * @param string $relative Relative URL to resolve
     * @return self New URL instance with resolved URL
     */
    public function resolve(string $relative): self;

    /**
     * Check equality with another URL
     *
     * @param self $other URL to compare
     * @param bool $includeFragment Whether to include fragment in comparison
     * @return bool True if URLs are equal
     */
    public function equals(self $other, bool $includeFragment = false): bool;

    /**
     * Get underlying native PHP URL object
     *
     * Provides access to native \Uri\Rfc3986\Uri or \Uri\WhatWg\Url
     * for advanced use cases requiring direct native API access.
     *
     * @return object Native PHP URL object
     */
    public function getNativeUrl(): object;
}
