import asyncio
import os

import httpx

from .errors import (
    DASHBOARD_URL,
    AuthenticationError,
    ConfigurationError,
    MCPConnectionError,
    OAuthError,
)

DEFAULT_BASE_URL = "https://taski-ai.com"


def _base_url() -> str:
    url = os.environ.get("AKASHIC_API_URL", DEFAULT_BASE_URL)
    return url.rstrip("/")

def fetch_connectors(api_key: str) -> list[dict]:
    """Call the Akashic API to get MCP connector URLs for the given agent key.

    Returns a list of dicts like [{"id": "...", "mcpUrl": "...", "serverLabel": "..."}].
    """
    url = f"{_base_url()}/api/tools"
    resp = httpx.get(url, headers={"Authorization": f"Bearer {api_key}"})

    if resp.status_code == 401:
        try:
            detail = resp.json().get("error", "")
        except (ValueError, KeyError):
            detail = ""
        raise AuthenticationError(
            f"API key rejected (HTTP 401){f': {detail}' if detail else ''}. "
            f"Verify the key is correct and active in your Akashic dashboard at {DASHBOARD_URL}."
        )

    try:
        resp.raise_for_status()
    except httpx.HTTPStatusError as exc:
        raise MCPConnectionError(
            f"Akashic API returned HTTP {resp.status_code}. "
            f"If this persists, check https://status.akashic.com or contact support."
        ) from exc

    data = resp.json()
    try:
        return data["connectors"]
    except KeyError:
        raise ConfigurationError(
            "Unexpected API response (missing 'connectors'). "
            "This agent may not have any connectors configured — "
            f"add them in the Akashic dashboard at {DASHBOARD_URL}."
        )


async def initiate_oauth(api_key: str, connector_id: str) -> dict:
    """POST /api/oauth/initiate → {authorizationUrl, sessionId}"""
    url = f"{_base_url()}/api/oauth/initiate"
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            url,
            json={"connectorId": connector_id},
            headers={"Authorization": f"Bearer {api_key}"},
        )
        if resp.status_code == 401:
            raise AuthenticationError(
                f"API key rejected (HTTP 401). "
                f"Verify the key is correct and active in your Akashic dashboard at {DASHBOARD_URL}."
            )
        if not resp.is_success:
            raise OAuthError(
                f"Could not start OAuth for connector '{connector_id}' (HTTP {resp.status_code}). "
                f"Check that this connector is properly configured in the dashboard at {DASHBOARD_URL}."
            )
        return resp.json()


async def poll_oauth_token(
    api_key: str, session_id: str, timeout: int = 300
) -> str:
    """Poll GET /api/oauth/token?sessionId=x every 2s until accessToken appears.

    Returns the access token string. Raises on timeout or failure.
    """
    url = f"{_base_url()}/api/oauth/token"
    deadline = asyncio.get_event_loop().time() + timeout

    async with httpx.AsyncClient() as client:
        while asyncio.get_event_loop().time() < deadline:
            resp = await client.get(
                url,
                params={"sessionId": session_id},
                headers={"Authorization": f"Bearer {api_key}"},
            )
            try:
                resp.raise_for_status()
            except httpx.HTTPStatusError as exc:
                raise MCPConnectionError(
                    f"Akashic API returned HTTP {resp.status_code} while polling OAuth token. "
                    f"If this persists, check https://status.akashic.com or contact support."
                ) from exc

            data = resp.json()

            if data.get("status") == "completed" and data.get("accessToken"):
                return data["accessToken"]
            if data.get("status") == "failed":
                detail = data.get("error", "no details provided")
                raise OAuthError(
                    f"OAuth authorization was denied or failed: {detail}. "
                    f"Try calling register() again to restart the sign-in flow."
                )

            await asyncio.sleep(2)

    raise OAuthError(
        f"OAuth sign-in was not completed within {timeout} seconds. "
        f"Call register() again to get a fresh authorization link."
    )
