"""Manage instance API."""

from __future__ import annotations

import logging
from typing import Literal, NotRequired, TypedDict

from aiohttp import hdrs

from .api import ApiBase, CloudApiError, api_exception_handler

_LOGGER = logging.getLogger(__name__)


class InstanceApiError(CloudApiError):
    """Exception raised when handling instance API."""


class InstanceConnectionDetails(TypedDict):
    """Connection details from instance API."""

    connected_at: str
    name: str
    remote_ip_address: str
    version: str


class InstanceConnectionConnnected(TypedDict):
    """Connection details from instance API."""

    connected: Literal[True]
    details: InstanceConnectionDetails


class InstanceConnectionDisconnected(TypedDict):
    """Connection details from instance API."""

    connected: Literal[False]


type InstanceConnection = InstanceConnectionConnnected | InstanceConnectionDisconnected


class InstanceRegistrationDetails(TypedDict):
    """Registration details from instance API."""

    alias: NotRequired[list[str]]
    domain: str
    email: str
    server: str


class InstanceSnitunTokenDetails(TypedDict):
    """Snitun token details from instance API."""

    token: str
    server: str
    valid: int
    throttling: int


class PingResult(TypedDict):
    """Ping result for a single target."""

    ip: str
    avg: float
    max: float
    min: float
    reachable: bool


class PingHost(TypedDict):
    """Host that can be pinged for latency measurement."""

    ip: str
    location: str


class PingTargetsResponse(TypedDict):
    """Response from ping targets API."""

    targets: list[PingHost]
    timeout: int
    count: int


class InstanceApi(ApiBase):
    """Class to help communicate with the instance API."""

    @api_exception_handler(InstanceApiError)
    async def connection(
        self,
        *,
        access_token: str | None = None,
        skip_token_check: bool = False,
    ) -> InstanceConnection:
        """Get the connection details."""
        _LOGGER.debug("Getting instance connection details")
        details: InstanceConnection = await self._call_cloud_api(
            action="instance_connection",
            headers={
                hdrs.AUTHORIZATION: access_token or self._cloud.access_token,
            },
            skip_token_check=skip_token_check,
        )
        return details

    @api_exception_handler(InstanceApiError)
    async def cleanup_dns_challenge_record(self, *, value: str) -> None:
        """Remove DNS challenge."""
        await self._call_cloud_api(
            method="POST",
            action="remote_access_dns_challenge_remove",
            jsondata={"txt": value},
        )

    @api_exception_handler(InstanceApiError)
    async def create_dns_challenge_record(self, *, value: str) -> None:
        """Set DNS challenge."""
        await self._call_cloud_api(
            method="POST",
            action="remote_access_dns_challenge_set",
            jsondata={"txt": value},
        )

    @api_exception_handler(InstanceApiError)
    async def ping_targets(self) -> PingTargetsResponse:
        """Get ping targets for latency measurement."""
        details: PingTargetsResponse = await self._call_cloud_api(
            action="remote_access_ping_targets",
        )
        return details

    @api_exception_handler(InstanceApiError)
    async def register(
        self,
        *,
        ping_result: list[PingResult] | None = None,
    ) -> InstanceRegistrationDetails:
        """Register the instance."""
        details: InstanceRegistrationDetails = await self._call_cloud_api(
            method="POST",
            action="remote_access_register",
            jsondata={"ping_result": ping_result} if ping_result is not None else None,
        )
        return details

    @api_exception_handler(InstanceApiError)
    async def snitun_token(
        self,
        *,
        aes_key: bytes,
        aes_iv: bytes,
    ) -> InstanceSnitunTokenDetails:
        """Create a remote snitun token."""
        details: InstanceSnitunTokenDetails = await self._call_cloud_api(
            method="POST",
            action="remote_access_snitun_token",
            jsondata={"aes_key": aes_key.hex(), "aes_iv": aes_iv.hex()},
        )
        return details
