import httpx
from models import ApiResult
from endpoints.cli import CLIEndpoint
from endpoints.vlan import VlanEndpoint
from endpoints.vpa import VlanPortAssociation
from endpoints.ip import IPInterfaceEndpoint
from endpoints.system import SystemEndpoint
from endpoints.interface import InterfaceEndpoint
from endpoints.mvrp import MvrpEndpoint
from endpoints.mac import MacLearningEndpoint

class AosApiClient:
    """
    API client for interacting with Alcatel-Lucent OmniSwitch AOS8 HTTP API.

    This client provides a high-level interface for authentication and making
    GET, POST, PUT, and DELETE requests to various AOS8 API endpoints.
    """

    def __init__(self, username: str, password: str, base_url: str, verify_ssl: bool = False, debug: bool = False):
        """
        Initialize the AOS API client and log in.

        Args:
            username: AOS API username.
            password: AOS API password.
            base_url: Base URL of the AOS device.
            verify_ssl: Whether to verify SSL certificates.
            debug: Enable debug logging.
        """
        self.username = username
        self.password = password
        self.base_url = base_url.rstrip('/')
        self.debug = debug
        self._client = httpx.Client(
            base_url=self.base_url,
            verify=verify_ssl,
            timeout=httpx.Timeout(10.0),
            headers={
                "Accept": "application/vnd.alcatellucentaos+json",
                "User-Agent": "AOSApiClient/1.0"
            }
        )
        self._login()

        self.cli = CLIEndpoint(self)
        self.vlan = VlanEndpoint(self)
        self.vpa = VlanPortAssociation(self)
        self.ip = IPInterfaceEndpoint(self)
        self.system = SystemEndpoint(self)
        self.interface = InterfaceEndpoint(self)
        self.mvrp = MvrpEndpoint(self)
        self.mac = MacLearningEndpoint(self)

    def _login(self):
        """
        Authenticate with the AOS API using provided credentials.

        Raises:
            Exception: If login fails or session cookie is not returned.
        """
        url = f"/auth/"
        params = {
            "username": self.username,
            "password": self.password,
        }
        response = self._client.get(url, params=params)
        if self.debug:
            print(f"🔐 Login response {response.status_code}: {response.text}")
        if response.status_code != 200:
            raise Exception("Login failed")
        if "wv_sess" not in self._client.cookies:
            raise Exception("Login succeeded but 'wv_sess' cookie not found")

    def _request(self, method: str, path: str, **kwargs) -> httpx.Response:
        """
        Send an HTTP request and handle re-authentication if necessary.

        Args:
            method: HTTP method (GET, POST, etc.)
            path: API endpoint path.
            **kwargs: Additional httpx request arguments.

        Returns:
            Response object.
        """
        if self.debug:
            print(f"➡️ {method} {path}")
            if "params" in kwargs:
                print("Params:", kwargs["params"])
            if "data" in kwargs:
                print("Form Data:", kwargs["data"])
            if "json" in kwargs:
                print("JSON:", kwargs["json"])

        response = self._client.request(method, path, **kwargs)

        if response.status_code == 401:
            print("🔁 401 Unauthorized. Re-authenticating...")
            self._login()
            response = self._client.request(method, path, **kwargs)

        if self.debug:
            print("⬅️ Response:", response.status_code, response.text)

        return self._handle_response(response)

    def _handle_response(self, response: httpx.Response) -> ApiResult:
        """
        Convert HTTP response into an ApiResult object.

        Args:
            response: httpx.Response object.

        Returns:
            Parsed ApiResult object.
        """
        try:
            result = response.json()
        except ValueError:
            return ApiResult(success=False, diag=response.status_code, error="Non-JSON response", output=response.text)

        r = result.get("result", {})
        diag = r.get("diag", 0)
        success = diag == 200

        return ApiResult(
            success=success,
            diag=diag,
            error=r.get("error"),
            output=r.get("output"),
            data=r.get("data")
        )

    def get(self, path: str, **kwargs) -> httpx.Response:
        """
        Send a GET request.

        Args:
            path: API endpoint path.
            **kwargs: Additional parameters for the request.

        Returns:
            Response object.
        """
        return self._request("GET", path, **kwargs)

    def post(self, path: str, data: dict = None, **kwargs) -> httpx.Response:
        """
        Send a POST request.

        Args:
            path: API endpoint path.
            data: Dictionary to send in the body.
            **kwargs: Additional parameters for the request.

        Returns:
            Response object.
        """
        kwargs.setdefault("data", data)
        return self._request("POST", path, **kwargs)

    def put(self, path: str, data: dict = None, **kwargs) -> httpx.Response:
        """
        Send a PUT request.

        Args:
            path: API endpoint path.
            data: Dictionary to send in the body.
            **kwargs: Additional parameters for the request.

        Returns:
            Response object.
        """
        kwargs.setdefault("data", data)
        return self._request("PUT", path, **kwargs)

    def delete(self, path: str, **kwargs) -> httpx.Response:
        """
        Send a DELETE request.

        Args:
            path: API endpoint path.
            **kwargs: Additional parameters for the request.

        Returns:
            Response object.
        """
        return self._request("DELETE", path, **kwargs)

    def close(self):
        """
        Close the underlying HTTP connection pool.
        """
        self._client.close()
