from typing import List, Optional, Any, Dict

from pydantic import BaseModel

POST = 'POST'
GET = 'GET'

class ResponseBase(BaseModel):
    success: bool
    msg: str
    obj: Optional[Any] = None


class MixedConfig(BaseModel):
    username: str
    password: str


class SocksConfig(BaseModel):
    username: str
    password: str


class HttpConfig(BaseModel):
    username: str
    password: str


class ShadowsocksConfig(BaseModel):
    name: str
    password: str


class Shadowsocks16Config(BaseModel):
    name: str
    password: str


class ShadowTLSConfig(BaseModel):
    name: str
    password: str


class VmessConfig(BaseModel):
    name: str
    uuid: str
    alterId: int


class VlessConfig(BaseModel):
    name: str
    uuid: str
    flow: Optional[str] = None


class AnytlsConfig(BaseModel):
    name: str
    password: str


class TrojanConfig(BaseModel):
    name: str
    password: str


class NaiveConfig(BaseModel):
    username: str
    password: str


class HysteriaConfig(BaseModel):
    name: str
    auth_str: str


class TuicConfig(BaseModel):
    name: str
    uuid: str
    password: str


class Hysteria2Config(BaseModel):
    name: str
    password: str


class ClientConfig(BaseModel):
    mixed: Optional[MixedConfig] = None
    socks: Optional[SocksConfig] = None
    http: Optional[HttpConfig] = None
    shadowsocks: Optional[ShadowsocksConfig] = None
    shadowsocks16: Optional[Shadowsocks16Config] = None
    shadowtls: Optional[ShadowTLSConfig] = None
    vmess: Optional[VmessConfig] = None
    vless: Optional[VlessConfig] = None
    anytls: Optional[AnytlsConfig] = None
    trojan: Optional[TrojanConfig] = None
    naive: Optional[NaiveConfig] = None
    hysteria: Optional[HysteriaConfig] = None
    tuic: Optional[TuicConfig] = None
    hysteria2: Optional[Hysteria2Config] = None


class ClientLink(BaseModel):
    remark: str
    type: str
    uri: str


class ClientItem(BaseModel):
    id: int
    name: str
    enable: bool
    inbounds: List[int]
    desc: Optional[str] = ""
    group: Optional[str] = ""
    up: Optional[int] = 0
    down: Optional[int] = 0
    volume: Optional[int] = 0
    expiry: Optional[int] = 0
    config: Optional[ClientConfig] = None
    links: Optional[List[ClientLink]] = None


class InboundItem(BaseModel):
    id: int
    listen: str
    listen_port: int
    tag: str
    tls_id: int
    type: str
    users: Optional[List[str]] = None


class ObfsConfig(BaseModel):
    password: str
    type: str


class TlsCertConfig(BaseModel):
    certificate: List[str]
    enabled: bool
    insecure: bool


class OutJson(BaseModel):
    obfs: Optional[ObfsConfig] = None
    server: Optional[str] = None
    server_port: Optional[int] = None
    tag: Optional[str] = None
    tls: Optional[TlsCertConfig] = None
    type: Optional[str] = None


class FullInbound(InboundItem):
    addrs: Optional[List[str]] = None
    ignore_client_bandwidth: Optional[bool] = None
    obfs: Optional[ObfsConfig] = None
    out_json: Optional[OutJson] = None


class OutboundTls(BaseModel):
    enabled: Optional[bool] = None
    insecure: Optional[bool] = None
    server_name: Optional[str] = None


class Outbound(BaseModel):
    id: Optional[int] = None
    tag: Optional[str] = None
    type: Optional[str] = None
    server: Optional[str] = None
    server_port: Optional[int] = None
    password: Optional[str] = None
    obfs: Optional[ObfsConfig] = None
    tls: Optional[OutboundTls] = None


class TLSHandshake(BaseModel):
    server: Optional[str] = None
    server_port: Optional[int] = None


class TLSReality(BaseModel):
    enabled: Optional[bool] = None
    handshake: Optional[TLSHandshake] = None
    short_id: Optional[List[str]] = None
    private_key: Optional[str] = None
    public_key: Optional[str] = None  # для client.reality


class TLSServer(BaseModel):
    enabled: Optional[bool] = None
    key: Optional[List[str]] = None
    certificate: Optional[List[str]] = None
    insecure: Optional[bool] = None
    server_name: Optional[str] = None
    reality: Optional[TLSReality] = None


class TLSClientUTLS(BaseModel):
    enabled: Optional[bool] = None
    fingerprint: Optional[str] = None


class TLSClient(BaseModel):
    insecure: Optional[bool] = None
    reality: Optional[TLSReality] = None
    utls: Optional[TLSClientUTLS] = None


class TLSItem(BaseModel):
    id: int
    name: str
    server: TLSServer
    client: TLSClient


class LogConfig(BaseModel):
    level: str


class DNSConfig(BaseModel):
    servers: List[str]
    rules: List[Any]


class RouteRule(BaseModel):
    action: str
    protocol: Optional[List[str]] = None
    method: Optional[str] = None
    rule_set: Optional[List[str]] = None
    rule_set_ip_cidr_match_source: Optional[bool] = None
    outbound: Optional[str] = None
    domain: Optional[List[str]] = None
    domain_suffix: Optional[List[str]] = None


class RouteRuleSet(BaseModel):
    type: str
    tag: str
    format: str
    url: str
    download_detour: str
    update_interval: str


class RouteConfig(BaseModel):
    rules: List[RouteRule]
    rule_set: List[RouteRuleSet]
    final: str


class ConfigData(BaseModel):
    log: LogConfig
    dns: DNSConfig
    route: RouteConfig
    experimental: Optional[Dict[str, Any]]


class InboundsObject(BaseModel):
    inbounds: List[FullInbound]


class ClientsObject(BaseModel):
    clients: Optional[List[ClientItem]] = None


class RemoveObject(BaseModel):
    clients: Optional[List[ClientItem]] = None
    inbounds: Optional[List[InboundItem]] = None


class OnlineObject(BaseModel):
    inbound: Optional[List[str]] = None
    user: Optional[List[str]] = None
    outbound: Optional[List[str]] = None


class OutboundsObject(BaseModel):
    outbounds: List[Outbound]


class EndpointsObject(BaseModel):
    endpoints: Optional[Any] = None


class ServicesObject(BaseModel):
    services: Optional[Any] = None


class GetConfigObject(BaseModel):
    config: ConfigData


class TLSObject(BaseModel):
    tls: List[TLSItem]


class DIOStats(BaseModel):
    read: int
    write: int


class DiskStats(BaseModel):
    current: int
    total: int


class MemStats(BaseModel):
    current: int
    total: int


class NetStats(BaseModel):
    precv: int
    psent: int
    recv: int
    sent: int


class SBDInnerStats(BaseModel):
    Alloc: int
    NumGoroutine: int
    Uptime: int


class SBDStats(BaseModel):
    running: bool
    stats: SBDInnerStats


class SwapStats(BaseModel):
    current: int
    total: int


class SysStats(BaseModel):
    appMem: int
    appThreads: int
    appVersion: str
    cpuCount: int
    cpuType: str
    hostName: str
    ipv4: List[str]
    ipv6: List[str]


class StatusObject(BaseModel):
    cpu: Optional[float] = None
    dio: Optional[DIOStats] = None
    dsk: Optional[DiskStats] = None
    mem: Optional[MemStats] = None
    net: Optional[NetStats] = None
    sbd: Optional[SBDStats] = None
    swp: Optional[SwapStats] = None
    sys: Optional[SysStats] = None
    uptime: Optional[int] = None


class AdminUser(BaseModel):
    id: Optional[int] = None
    username: Optional[str] = None
    password: Optional[str] = None
    lastLogin: Optional[str] = None


class PanelSettings(BaseModel):
    sessionMaxAge: Optional[str] = None
    subCertFile: Optional[str] = None
    subClashExt: Optional[str] = None
    subDomain: Optional[str] = None
    subEncode: Optional[str] = None
    subJsonExt: Optional[str] = None
    subKeyFile: Optional[str] = None
    subListen: Optional[str] = None
    subPath: Optional[str] = None
    subPort: Optional[str] = None
    subShowInfo: Optional[str] = None
    subURI: Optional[str] = None
    subUpdates: Optional[str] = None
    timeLocation: Optional[str] = None
    trafficAge: Optional[str] = None
    webCertFile: Optional[str] = None
    webDomain: Optional[str] = None
    webKeyFile: Optional[str] = None
    webListen: Optional[str] = None
    webPath: Optional[str] = None
    webPort: Optional[str] = None
    webURI: Optional[str] = None


class GetServicesResponse(ResponseBase):
    obj: Optional[ServicesObject] = None


class GetEndpointsResponse(ResponseBase):
    obj: Optional[EndpointsObject] = None


class GetOutboundsResponse(ResponseBase):
    obj: Optional[OutboundsObject] = None


class GetInboundsResponse(ResponseBase):
    obj: Optional[InboundsObject] = None


class GetOnlineResponse(ResponseBase):
    obj: Optional[OnlineObject] = None


class RemoveResponse(ResponseBase):
    obj: Optional[RemoveObject] = None


class GetClientsUniversalResponse(ResponseBase):
    obj: Optional[ClientsObject] = None


class GetTLSResponse(ResponseBase):
    obj: TLSObject


class GetConfigResponse(ResponseBase):
    obj: GetConfigObject


class GetStatsResponse(ResponseBase):
    pass


class GetStatusResponse(ResponseBase):
    obj: StatusObject


class LogsResponse(ResponseBase):
    obj: Optional[List[str]] = None


class AdminsResponse(ResponseBase):
    obj: Optional[List[AdminUser]] = None


class SettingsResponse(ResponseBase):
    obj: PanelSettings