from datetime import datetime
from typing import Annotated, List, Optional
from uuid import UUID

from pydantic import (
    BaseModel,
    Field,
    RootModel,
    StringConstraints,
)

from remnawave.enums import TrafficLimitStrategy, UserStatus


class UserActiveInboundsDto(BaseModel):
    uuid: UUID
    tag: str
    type: str
    network: str | None = None
    security: str | None = None


class UserLastConnectedNodeDto(BaseModel):
    connected_at: datetime = Field(alias="connectedAt")
    node_name: str = Field(alias="nodeName")


class ActiveInternalSquadDto(BaseModel):
    uuid: UUID
    name: str


class HappCrypto(BaseModel):
    cryptoLink: str


class CreateUserRequestDto(BaseModel):
    expire_at: datetime = Field(..., serialization_alias="expireAt")
    username: Annotated[
        str, StringConstraints(pattern=r"^[a-zA-Z0-9_-]+$", min_length=3, max_length=36)
    ]
    created_at: datetime | None = Field(None, serialization_alias="createdAt")
    status: UserStatus | None = None
    short_uuid: str | None = Field(None, serialization_alias="shortUuid")
    trojan_password: Annotated[
        str | None, StringConstraints(min_length=8, max_length=32)
    ] = Field(None, serialization_alias="trojanPassword")
    vless_uuid: str | None = Field(None, serialization_alias="vlessUuid")
    ss_password: Annotated[
        str | None, StringConstraints(min_length=8, max_length=32)
    ] = Field(None, serialization_alias="ssPassword")
    traffic_limit_bytes: int | None = Field(
        None, serialization_alias="trafficLimitBytes", strict=True, ge=0
    )
    traffic_limit_strategy: TrafficLimitStrategy | None = Field(
        None, serialization_alias="trafficLimitStrategy"
    )
    last_traffic_reset_at: datetime | None = Field(
        None, serialization_alias="lastTrafficResetAt"
    )
    description: str | None = None
    tag: str | None = None
    telegram_id: int | None = Field(None, serialization_alias="telegramId")
    email: str | None = None
    hwidDeviceLimit: int | None = Field(
        None, serialization_alias="hwidDeviceLimit", strict=True, ge=0
    )
    active_internal_squads: list[str] | None = Field(
        None, serialization_alias="activeInternalSquads"
    )
    uuid: Optional[UUID] = Field(None, description="UUID of the user. Optional. If not provided, a new UUID will be generated by Remnawave.")


class UpdateUserRequestDto(BaseModel):
    uuid: UUID
    active_internal_squads: list[str] | None = Field(
        None, serialization_alias="activeInternalSquads"
    )
    description: str | None = None
    email: str | None = None
    expire_at: datetime | None = Field(None, serialization_alias="expireAt")
    hwidDeviceLimit: int | None = Field(
        None, serialization_alias="hwidDeviceLimit", strict=True, ge=0
    )
    status: UserStatus | None = None
    tag: str | None = None
    telegram_id: int | None = Field(None, serialization_alias="telegramId")
    traffic_limit_bytes: int | None = Field(
        None, serialization_alias="trafficLimitBytes", strict=True, ge=0
    )
    traffic_limit_strategy: TrafficLimitStrategy | None = Field(
        None, serialization_alias="trafficLimitStrategy"
    )


class UserResponseDto(BaseModel):
    uuid: UUID
    short_uuid: str = Field(alias="shortUuid")
    username: str
    status: UserStatus | None = None
    used_traffic_bytes: float = Field(alias="usedTrafficBytes")
    lifetime_used_traffic_bytes: float = Field(alias="lifetimeUsedTrafficBytes")
    traffic_limit_bytes: int | None = Field(None, alias="trafficLimitBytes")
    traffic_limit_strategy: str | None = Field(None, alias="trafficLimitStrategy")
    sub_last_user_agent: str | None = Field(None, alias="subLastUserAgent")
    sub_last_opened_at: datetime | None = Field(None, alias="subLastOpenedAt")
    expire_at: datetime | None = Field(None, alias="expireAt")
    online_at: datetime | None = Field(None, alias="onlineAt")
    sub_revoked_at: datetime | None = Field(None, alias="subRevokedAt")
    last_traffic_reset_at: datetime | None = Field(None, alias="lastTrafficResetAt")
    trojan_password: str = Field(alias="trojanPassword")
    vless_uuid: UUID = Field(alias="vlessUuid")
    ss_password: str = Field(alias="ssPassword")
    description: str | None = None
    telegram_id: int | None = Field(None, alias="telegramId")
    email: str | None = None
    hwidDeviceLimit: int | None = Field(
        None, serialization_alias="hwidDeviceLimit", strict=True, ge=0
    )
    active_internal_squads: list[ActiveInternalSquadDto] | None = Field(
        None, alias="activeInternalSquads"
    )
    subscription_url: str | None = Field(None, alias="subscriptionUrl")
    first_connected: datetime | None = Field(None, alias="firstConnectedAt")
    last_trigger_threshold: int | None = Field(None, alias="lastTriggeredThreshold")
    last_connected_node: UserLastConnectedNodeDto | None = Field(
        None, alias="lastConnectedNode"
    )
    happ: HappCrypto | None = Field(None, alias="happ")
    tag: str | None = Field(None, alias="tag")
    created_at: datetime = Field(alias="createdAt")
    updated_at: datetime = Field(alias="updatedAt")


class EmailUserResponseDto(RootModel[list[UserResponseDto]]):
    def __iter__(self):
        return iter(self.root)

    def __getitem__(self, item):
        return self.root[item]


class TagUserResponseDto(RootModel[list[UserResponseDto]]):
    def __iter__(self):
        return iter(self.root)

    def __getitem__(self, item):
        return self.root[item]


class TelegramUserResponseDto(RootModel[list[UserResponseDto]]):
    def __iter__(self):
        return iter(self.root)

    def __getitem__(self, item):
        return self.root[item]


class UsersResponseDto(BaseModel):
    users: list[UserResponseDto]
    total: float


class DeleteUserResponseDto(BaseModel):
    is_deleted: bool = Field(alias="isDeleted")


class TagsResponseDto(BaseModel):
    tags: list[str]


class CreateUserResponseDto(UserResponseDto):
    pass


class UpdateUserResponseDto(UserResponseDto):
    pass


class DisableUserResponseDto(UserResponseDto):
    pass


class EnableUserResponseDto(UserResponseDto):
    pass


class ResetUserTrafficResponseDto(UserResponseDto):
    pass


class RevokeUserSubscriptionResponseDto(UserResponseDto):
    pass


class ActivateAllInboundsResponseDto(UserResponseDto):
    pass


class GetUserByUuidResponseDto(UserResponseDto):
    pass


class GetUserByShortUuidResponseDto(UserResponseDto):
    pass


class GetUserByUsernameResponseDto(UserResponseDto):
    pass


class RevokeUserRequestDto(BaseModel):
    short_uuid: str | None = Field(
        None,
        serialization_alias="shortUuid",
        description="Optional. If not provided, a new short UUID will be generated by Remnawave. Please note that it is strongly recommended to allow Remnawave to generate the short UUID.",
        min_length=6,
        max_length=48,
        pattern=r"^[a-zA-Z0-9_-]+$",
    )


class SubscriptionRequestRecord(BaseModel):
    id: int
    user_uuid: UUID = Field(alias="userUuid")
    request_at: datetime = Field(alias="requestAt")
    request_ip: Optional[str] = Field(alias="requestIp")
    user_agent: Optional[str] = Field(alias="userAgent")


class SubscriptionRequestsResponseData(BaseModel):
    total: float
    records: List[SubscriptionRequestRecord]


class GetSubscriptionRequestsResponseDto(SubscriptionRequestsResponseData):
    pass