from typing import Any, Optional

from pydantic import (
    AfterValidator,
    AnyHttpUrl,
    AnyUrl,
    GetCoreSchemaHandler,
    GetJsonSchemaHandler,
    TypeAdapter,
)
from pydantic.json_schema import JsonSchemaValue
from pydantic_core import Url
from pydantic_core.core_schema import CoreSchema, no_info_after_validator_function
from typing_extensions import Annotated

StrNoTrailingSlash = Annotated[str, AfterValidator(lambda x: str(x).rstrip("/"))]
StrNoLeadingSlash = Annotated[str, AfterValidator(lambda x: str(x).lstrip("/"))]


class AnyUrlStr(str):
    _type_adapter = TypeAdapter(AnyUrl)
    obj: Url

    @classmethod
    def __get_pydantic_core_schema__(
        cls,
        _: Any,
        handler: GetCoreSchemaHandler,
    ) -> CoreSchema:
        return no_info_after_validator_function(cls, handler(str))

    @classmethod
    def __get_pydantic_json_schema__(
        cls,
        core_schema: CoreSchema,
        handler: GetJsonSchemaHandler,
    ) -> JsonSchemaValue:
        field_schema = handler(core_schema)
        field_schema.update(format="uri")
        return field_schema

    def __new__(cls, value: str) -> "AnyUrlStr":
        url_obj = cls._type_adapter.validate_strings(value)
        self = str.__new__(cls, str(url_obj).rstrip("/"))
        self.obj = url_obj
        return self

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}({super().__repr__()})"

    @property
    def scheme(self) -> str:
        return self.obj.scheme

    @property
    def host(self) -> Optional[str]:
        return self.obj.host

    @property
    def port(self) -> Optional[int]:
        return self.obj.port

    @property
    def path(self) -> Optional[str]:
        return self.obj.path


class AnyHttpUrlStr(AnyUrlStr):
    _type_adapter = TypeAdapter(AnyHttpUrl)