"""API для работы с нодами."""

from typing import Optional, TYPE_CHECKING

from .models import Node
from .exceptions import NotFoundError, APIError

if TYPE_CHECKING:
    from .client import AmnezioClient


class NodesAPI:
    """API для работы с нодами."""
    
    def __init__(self, client: "AmnezioClient"):
        self.client = client
    
    async def list(self, profile_id: Optional[int] = None) -> list[Node]:
        """
        Получить список нод.
        
        Args:
            profile_id: Фильтр по профилю (опционально)
        
        Returns:
            Список нод
        """
        params = {}
        if profile_id is not None:
            params["profile_id"] = profile_id
        
        response = await self.client.request("GET", "/api/nodes", params=params)
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return [Node(**item) for item in response.json()]
    
    async def create(
        self,
        name: str,
        host: str,
        node_port: int = 9999,
        profile_id: Optional[int] = None,
    ) -> dict:
        """
        Создать ноду.
        
        Args:
            name: Название ноды
            host: Хост ноды (IP или домен)
            node_port: Порт агента
            profile_id: ID профиля
        
        Returns:
            Данные созданной ноды с SECRET_KEY и docker-compose
        """
        data = {
            "name": name,
            "host": host,
            "node_port": node_port,
        }
        
        if profile_id:
            data["profile_id"] = profile_id
        
        response = await self.client.request("POST", "/api/nodes", json=data)
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return response.json()
    
    async def get(self, node_id: int) -> Node:
        """
        Получить ноду по ID.
        
        Args:
            node_id: ID ноды
        
        Returns:
            Нода
        """
        response = await self.client.request("GET", f"/api/nodes/{node_id}")
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return Node(**response.json())
    
    async def update(
        self,
        node_id: int,
        name: Optional[str] = None,
        host: Optional[str] = None,
        node_port: Optional[int] = None,
        profile_id: Optional[int] = None,
    ) -> Node:
        """
        Обновить ноду.
        
        Args:
            node_id: ID ноды
            name: Название ноды
            host: Хост ноды
            node_port: Порт агента
            profile_id: ID профиля
        
        Returns:
            Обновленная нода
        """
        data = {}
        
        if name is not None:
            data["name"] = name
        if host is not None:
            data["host"] = host
        if node_port is not None:
            data["node_port"] = node_port
        if profile_id is not None:
            data["profile_id"] = profile_id
        
        response = await self.client.request("PUT", f"/api/nodes/{node_id}", json=data)
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return Node(**response.json())
    
    async def delete(self, node_id: int) -> dict:
        """
        Удалить ноду.
        
        Args:
            node_id: ID ноды
        
        Returns:
            Статус операции
        """
        response = await self.client.request("DELETE", f"/api/nodes/{node_id}")
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return response.json()
    
    async def sync(self, node_id: int) -> dict:
        """
        Синхронизировать ноду (GET / на агенте).
        
        Args:
            node_id: ID ноды
        
        Returns:
            Данные синхронизации
        """
        response = await self.client.request("POST", f"/api/nodes/{node_id}/sync")
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return response.json()
    
    async def push_config(self, node_id: int) -> dict:
        """
        Отправить конфиг на ноду (POST /config на агенте).
        
        Args:
            node_id: ID ноды
        
        Returns:
            Статус операции
        """
        response = await self.client.request("POST", f"/api/nodes/{node_id}/push-config")
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return response.json()
    
    async def restart(self, node_id: int) -> dict:
        """
        Перезапустить AmneziaWG на ноде (POST /restart на агенте).
        
        Args:
            node_id: ID ноды
        
        Returns:
            Статус операции
        """
        response = await self.client.request("POST", f"/api/nodes/{node_id}/restart")
        
        if response.status_code == 404:
            raise NotFoundError(f"Нода {node_id} не найдена")
        
        if response.status_code != 200:
            raise APIError(response.status_code, response.text)
        
        return response.json()
