# -*- coding: utf-8 -*-
"""
@File    : types.py
@Author  : Jay
@Date    : 2026/3/19 9:21
@Desc    : Data models for Redis configuration and rate-limited containers.
"""
import ssl
import time
from typing import Callable, List, Mapping, Optional, Type, Union

from pydantic import BaseModel, Field
from redis.backoff import ExponentialWithJitterBackoff
from redis.credentials import CredentialProvider
from redis.event import EventDispatcher
from redis.retry import Retry
from redis.utils import get_lib_version

# Aliases for SSL/TLS constants
SSLVerifyMode = ssl.VerifyMode
SSLVerifyFlags = ssl.VerifyFlags
SSLTLSVersion = ssl.TLSVersion


class RedisConfigModel(BaseModel):
    """Pydantic model representing Redis connection configuration."""

    host: Union[str] = Field("localhost", description="Redis server host")
    port: Union[int, str] = Field(6379, description="Redis server port")
    db: Union[int, str] = Field(0, description="Redis database index")
    password: Optional[str] = Field(None, description="Redis password")
    socket_timeout: Optional[float] = Field(None, description="Socket timeout in seconds")
    socket_connect_timeout: Optional[float] = Field(None, description="Socket connection timeout in seconds")
    socket_keepalive: Optional[bool] = Field(None, description="Enable TCP Keepalive")
    socket_keepalive_options: Optional[Mapping[int, Union[int, bytes]]] = Field(
        default_factory=dict, description="TCP Keepalive options"
    )
    encoding: Union[str] = Field("utf-8", description="Encoding for Redis responses")
    encoding_errors: Union[str] = Field("strict", description="Encoding error handling mode")
    decode_responses: Union[bool] = Field(False, description="Decode byte responses to strings")
    retry_on_timeout: Union[bool] = Field(False, description="Retry operations on timeout")
    retry: Retry = Field(
        default_factory=lambda: Retry(backoff=ExponentialWithJitterBackoff(base=1, cap=10), retries=3),
        description="Retry strategy object"
    )
    retry_on_error: Optional[List[Type[Exception]]] = Field(default_factory=list, description="Exceptions to retry on")
    max_connections: Optional[int] = Field(None, description="Maximum number of connections")
    health_check_interval: int = Field(0, description="Health check interval in seconds")
    client_name: Optional[str] = Field(None, description="Client name for Redis connections")
    lib_name: Optional[str] = Field("redis-py", description="Client library name")
    lib_version: Optional[str] = Field(default_factory=get_lib_version, description="Client library version")
    username: Optional[str] = Field(None, description="Username for ACL authentication")
    redis_connect_func: Optional[Callable[[], None]] = Field(None, description="Custom Redis connection function")
    credential_provider: Optional[CredentialProvider] = Field(None, description="Credential provider instance")
    protocol: Optional[int] = Field(2, description="Redis protocol version")
    event_dispatcher: Optional[EventDispatcher] = Field(None, description="Event dispatcher for Redis events")

    model_config = {
        "extra": "allow",  # Allow extra fields not defined in the model
        "arbitrary_types_allowed": True  # Allow arbitrary non-Pydantic types, e.g., Retry
    }


class LimitedModel(BaseModel):
    """Model for rate-limited container entries."""

    id: str = Field(..., description="Unique identifier for the data")
    ct: Optional[int] = Field(
        default_factory=lambda: int(time.time() * 1000),
        description="Collection timestamp in milliseconds"
    )
    ttl_ms: Optional[int] = Field(default=0, description="Time-to-live in milliseconds")
    interval_ms: Optional[int] = Field(
        default=0,
        description="Rate limiting interval in milliseconds (0 means no limit)"
    )
    next_time_available: Optional[int] = Field(
        default_factory=lambda: int(time.time() * 1000),
        description="Next available timestamp in milliseconds"
    )
    containers: Optional[str] = Field(default=None, description="Container to store the data")
    usage_count: Optional[int] = Field(default=0, description="Number of times this entry has been accessed")


__all__ = ["RedisConfigModel", "LimitedModel"]
