"""
PowerBI REST API client

Handles all interactions with PowerBI REST API endpoints.
"""

import logging
from typing import Any, Optional

import httpx

from .auth import PowerBIAuth
from .constants import API_BASE_URL, API_TIMEOUT
from .exceptions import handle_http_error

logger = logging.getLogger(__name__)


class PowerBIClient:
    """PowerBI REST API client"""

    def __init__(self, auth: PowerBIAuth):
        """
        Initialize PowerBI API client

        Args:
            auth: PowerBIAuth instance for handling authentication
        """
        self.auth = auth
        self.http_client = httpx.AsyncClient(timeout=API_TIMEOUT)
        logger.info("PowerBI API client initialized")

    async def _make_request(
        self,
        method: str,
        endpoint: str,
        **kwargs
    ) -> dict[str, Any]:
        """
        Make authenticated request to PowerBI API

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

        Returns:
            JSON response from API

        Raises:
            Exception: If API request fails with actionable error message
        """
        token = await self.auth.get_access_token()

        headers = kwargs.get("headers", {})
        headers["Authorization"] = f"Bearer {token}"
        headers["Content-Type"] = "application/json"
        kwargs["headers"] = headers

        url = f"{API_BASE_URL}{endpoint}"

        try:
            logger.debug(f"{method} {url}")
            response = await self.http_client.request(method, url, **kwargs)
            response.raise_for_status()
            return response.json()

        except httpx.HTTPStatusError as e:
            # Use centralized error handler
            raise handle_http_error(e, "API request") from e

        except httpx.TimeoutException as e:
            logger.error(f"Request timeout for endpoint: {endpoint}")
            raise Exception(
                f"Request to PowerBI API timed out for endpoint: {endpoint}. "
                "The operation took too long. Try reducing the scope of your query "
                "or check PowerBI service status."
            ) from e
        except Exception as e:
            if isinstance(e, Exception) and "PowerBI" in str(e):
                raise
            logger.error(f"Unexpected error: {e}")
            raise Exception(f"Unexpected error while calling PowerBI API: {str(e)}") from e

    async def get_workspaces(
        self,
        top: Optional[int] = None,
        skip: Optional[int] = None
    ) -> dict[str, Any]:
        """
        Get list of workspaces (groups)

        Args:
            top: Maximum number of workspaces to return (pagination)
            skip: Number of workspaces to skip (pagination)

        Returns:
            Dictionary with 'value' key containing list of workspaces
        """
        params = {}
        if top is not None:
            params["$top"] = top
        if skip is not None:
            params["$skip"] = skip

        logger.info(f"Fetching workspaces (top={top}, skip={skip})")
        return await self._make_request("GET", "/groups", params=params)

    async def get_datasets(
        self,
        workspace_id: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Get list of datasets from workspace or My workspace

        Args:
            workspace_id: Workspace (group) ID. If None, returns datasets from "My workspace"

        Returns:
            Dictionary with 'value' key containing list of datasets
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/datasets"
            logger.info(f"Fetching datasets from workspace {workspace_id}")
        else:
            endpoint = "/datasets"
            logger.info("Fetching datasets from My workspace")

        return await self._make_request("GET", endpoint)

    async def get_dataset(
        self,
        dataset_id: str,
        workspace_id: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Get details of a specific dataset

        Args:
            dataset_id: Dataset ID
            workspace_id: Workspace (group) ID. If None, looks in "My workspace"

        Returns:
            Dataset details dictionary
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/datasets/{dataset_id}"
            logger.info(f"Fetching dataset {dataset_id} from workspace {workspace_id}")
        else:
            endpoint = f"/datasets/{dataset_id}"
            logger.info(f"Fetching dataset {dataset_id} from My workspace")

        return await self._make_request("GET", endpoint)

    async def execute_queries(
        self,
        dataset_id: str,
        queries: list[dict[str, str]],
        workspace_id: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Execute DAX queries against a dataset

        Args:
            dataset_id: Dataset ID to query
            queries: List of query dictionaries with 'query' key containing DAX expression
            workspace_id: Workspace (group) ID. If None, uses "My workspace"

        Returns:
            Query results dictionary
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/datasets/{dataset_id}/executeQueries"
            logger.info(f"Executing {len(queries)} queries on dataset {dataset_id} in workspace {workspace_id}")
        else:
            endpoint = f"/datasets/{dataset_id}/executeQueries"
            logger.info(f"Executing {len(queries)} queries on dataset {dataset_id} in My workspace")

        payload = {"queries": queries}

        return await self._make_request("POST", endpoint, json=payload)

    async def get_refresh_history(
        self,
        dataset_id: str,
        workspace_id: Optional[str] = None,
        top: int = 5
    ) -> dict[str, Any]:
        """
        Get refresh history for a dataset

        Args:
            dataset_id: Dataset ID
            workspace_id: Workspace (group) ID. If None, uses "My workspace"
            top: Number of refresh records to return (default: 5)

        Returns:
            Dictionary with 'value' containing refresh history records
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/datasets/{dataset_id}/refreshes"
            logger.info(f"Fetching refresh history for dataset {dataset_id} in workspace {workspace_id}")
        else:
            endpoint = f"/datasets/{dataset_id}/refreshes"
            logger.info(f"Fetching refresh history for dataset {dataset_id} in My workspace")

        params = {"$top": top}
        return await self._make_request("GET", endpoint, params=params)

    async def get_parameters(
        self,
        dataset_id: str,
        workspace_id: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Get parameters for a dataset

        Args:
            dataset_id: Dataset ID
            workspace_id: Workspace (group) ID. If None, uses "My workspace"

        Returns:
            Dictionary with 'value' containing parameter definitions
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/datasets/{dataset_id}/parameters"
            logger.info(f"Fetching parameters for dataset {dataset_id} in workspace {workspace_id}")
        else:
            endpoint = f"/datasets/{dataset_id}/parameters"
            logger.info(f"Fetching parameters for dataset {dataset_id} in My workspace")

        return await self._make_request("GET", endpoint)

    async def get_reports(
        self,
        workspace_id: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Get reports from workspace or My workspace

        Args:
            workspace_id: Workspace (group) ID. If None, uses "My workspace"

        Returns:
            Dictionary with 'value' containing report list
        """
        if workspace_id:
            endpoint = f"/groups/{workspace_id}/reports"
            logger.info(f"Fetching reports from workspace {workspace_id}")
        else:
            endpoint = "/reports"
            logger.info("Fetching reports from My workspace")

        return await self._make_request("GET", endpoint)

    async def close(self) -> None:
        """Close HTTP client and cleanup resources"""
        await self.http_client.aclose()
        logger.info("PowerBI API client closed")
