import json

from ..errors import NotFound
from ..models.models import (
    POST,
    GET,
    GetClientsUniversalResponse,
    RemoveResponse,
    GetOnlineResponse
)
from ..service.generate_password import generate_client_config


class Client:

    async def get_clients(
        self,
        client_id: int = None
    ) -> GetClientsUniversalResponse:
        data = {}
        if client_id is not None:
            data['id'] = client_id
        result = await self.request(
            method=GET,
            endpoint='/apiv2/clients',
            params=data,
        )
        if result.get('obj') is None:
            raise NotFound()
        if result.get('obj').get('clients') is None:
            raise NotFound()
        return GetClientsUniversalResponse(**result)

    async def add_client(
        self,
        name: str,
        password: str,
        inbounds_id: list[int],
        description: str = "",
        group: str = "",
        volume: int = 0,
        expiry: int = 0
    ) -> GetClientsUniversalResponse:
        client_data = {
            "enable": True,
            "name": name,
            "config": generate_client_config(name, password),
            "inbounds": inbounds_id,
            "links": [],
            "volume": volume,
            "expiry": expiry,
            "up": 0,
            "down": 0,
            "desc": description,
            "group": group
        }
        json_str = json.dumps(client_data, separators=(',', ':'))
        form_data = {
            'object': 'clients',
            'action': 'new',
            'data': json_str,
        }
        result = await self.request(
            method=POST,
            endpoint='/apiv2/save',
            data=form_data,
        )
        return GetClientsUniversalResponse(**result)

    async def delete_client(self, user_id: int) -> RemoveResponse:
        form_data = {
            'object': 'clients',
            'action': 'del',
            'data': str(user_id),
        }
        result = await self.request(
            method=POST,
            endpoint='/apiv2/save',
            data=form_data,
        )
        return RemoveResponse(**result)

    async def get_online(self) -> GetOnlineResponse:
        result = await self.request(
            method=GET,
            endpoint='/apiv2/onlines',
        )
        return GetOnlineResponse(**result)

    async def update_client(
        self,
        user_id: int,
        enable: bool | None = None,
        desc: str | None = None,
        group: str | None = None,
        up: int | None = None,
        down: int | None = None,
        volume: int | None = None,
        expiry: int | None = None,
    ):
        client = await self.get_clients(client_id=user_id)
        client = client.obj.clients[0]

        if enable is not None:
            client.enable = enable
        if desc is not None:
            client.desc = desc
        if group is not None:
            client.group = group
        if up is not None:
            client.up = up
        if down is not None:
            client.down = down
        if volume is not None:
            client.volume = volume
        if expiry is not None:
            client.expiry = expiry

        client_dict = {
            "id": client.id,
            "enable": client.enable,
            "name": client.name,
            "desc": client.desc,
            "group": client.group,
            "inbounds": client.inbounds,
            "up": client.up,
            "down": client.down,
            "volume": client.volume,
            "expiry": client.expiry,
            "config": {
                "mixed": {
                    "username": client.config.mixed.username,
                    "password": client.config.mixed.password
                },
                "socks": {
                    "username": client.config.socks.username,
                    "password": client.config.socks.password
                },
                "http": {
                    "username": client.config.http.username,
                    "password": client.config.http.password
                },
                "shadowsocks": {
                    "name": client.config.shadowsocks.name,
                    "password": client.config.shadowsocks.password
                },
                "shadowsocks16": {
                    "name": client.config.shadowsocks16.name,
                    "password": client.config.shadowsocks16.password
                },
                "shadowtls": {
                    "name": client.config.shadowtls.name,
                    "password": client.config.shadowtls.password
                },
                "vmess": {
                    "name": client.config.vmess.name,
                    "uuid": client.config.vmess.uuid,
                    "alterId": client.config.vmess.alterId
                },
                "vless": {
                    "name": client.config.vless.name,
                    "uuid": client.config.vless.uuid,
                    "flow": client.config.vless.flow
                },
                "anytls": {
                    "name": client.config.anytls.name,
                    "password": client.config.anytls.password
                },
                "trojan": {
                    "name": client.config.trojan.name,
                    "password": client.config.trojan.password
                },
                "naive": {
                    "username": client.config.naive.username,
                    "password": client.config.naive.password
                },
                "hysteria": {
                    "name": client.config.hysteria.name,
                    "auth_str": client.config.hysteria.auth_str
                },
                "tuic": {
                    "name": client.config.tuic.name,
                    "uuid": client.config.tuic.uuid,
                    "password": client.config.tuic.password
                },
                "hysteria2": {
                    "name": client.config.hysteria2.name,
                    "password": client.config.hysteria2.password
                }
            },
            "links": []
        }
        json_data = json.dumps(client_dict, separators=(',', ':'))
        form_data = {
            'object': 'clients',
            'action': 'edit',
            'data': json_data,
            'hostname': self.base_url.split("//")[1].split("/")[0]
        }
        result = await self.request(
            method=POST,
            endpoint='/apiv2/save',
            data=form_data,
        )
        return GetClientsUniversalResponse(**result)
