from typing import Optional

from pydantic import GetCoreSchemaHandler
from pydantic_core import core_schema


class Time:
    def __init__(
        self,
        year: Optional[int] = None,
        month: Optional[int] = None,
        day: Optional[int] = None,
        hour: Optional[int] = None,
        minute: Optional[int] = None,
    ):
        self.year = year
        self.month = month
        self.day = day
        self.hour = hour
        self.minute = minute

    def __str__(self) -> str:
        parts = []
        if self.year is not None:
            parts.append(f"year={self.year}")
        if self.month is not None:
            parts.append(f"month={self.month}")
        if self.day is not None:
            parts.append(f"day={self.day}")
        if self.hour is not None:
            parts.append(f"hour={self.hour}")
        if self.minute is not None:
            parts.append(f"minute={self.minute}")
        
        return ", ".join(parts) if parts else "Time()"

    def __repr__(self) -> str:
        parts = []
        if self.year is not None:
            parts.append(f"year={self.year}")
        if self.month is not None:
            parts.append(f"month={self.month}")
        if self.day is not None:
            parts.append(f"day={self.day}")
        if self.hour is not None:
            parts.append(f"hour={self.hour}")
        if self.minute is not None:
            parts.append(f"minute={self.minute}")
        
        return f"Time({', '.join(parts)})" if parts else "Time()"

    def _comparison_key(self) -> tuple[int, int, int, int, int, int]:
        def _normalize(value: Optional[int]) -> int:
            return value if value is not None else -1

        specificity = sum(
            1
            for value in (self.year, self.month, self.day, self.hour, self.minute)
            if value is not None
        )
        return (
            _normalize(self.year),
            _normalize(self.month),
            _normalize(self.day),
            _normalize(self.hour),
            _normalize(self.minute),
            specificity,
        )

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return (
            self.year,
            self.month,
            self.day,
            self.hour,
            self.minute,
        ) == (
            other.year,
            other.month,
            other.day,
            other.hour,
            other.minute,
        )

    def __lt__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._comparison_key() < other._comparison_key()

    def __le__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._comparison_key() <= other._comparison_key()

    def __gt__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._comparison_key() > other._comparison_key()

    def __ge__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._comparison_key() >= other._comparison_key()

    def __hash__(self) -> int:
        return hash((self.year, self.month, self.day, self.hour, self.minute))

    @classmethod
    def __get_pydantic_core_schema__(cls, source_type: type, handler: GetCoreSchemaHandler):
        return core_schema.is_instance_schema(
            cls,
            serialization=core_schema.plain_serializer_function_ser_schema(
                lambda value: {
                    "year": value.year,
                    "month": value.month,
                    "day": value.day,
                    "hour": value.hour,
                    "minute": value.minute,
                },
                return_schema=core_schema.dict_schema(
                    keys_schema=core_schema.str_schema(),
                    values_schema=core_schema.any_schema(),
                ),
            ),
        )

