import asyncio
import logging

from ._types import AuthContext
from .config import get_account_url, get_credentials, is_auth_disabled

logger = logging.getLogger("iis_access")

_cached_context: AuthContext | None = None
_refresh_lock: asyncio.Lock | None = None


def _get_lock() -> asyncio.Lock:
    global _refresh_lock
    if _refresh_lock is None:
        _refresh_lock = asyncio.Lock()
    return _refresh_lock


async def get_auth_context() -> AuthContext | None:
    """Get authentication context. Returns None if not authenticated."""
    global _cached_context

    if is_auth_disabled():
        return None

    if _cached_context is not None:
        return _cached_context

    async with _get_lock():
        # Double-check after acquiring lock
        if _cached_context is not None:
            return _cached_context

        creds = get_credentials()
        if not creds or "accountId" not in creds:
            return None

        account_id = creds["accountId"]
        refresh_token = _get_refresh_token(account_id)
        if not refresh_token:
            return None

        # Exchange refresh token for access token
        try:
            import aiohttp

            account_url = get_account_url()
            timeout = aiohttp.ClientTimeout(total=5)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                resp = await session.post(
                    f"{account_url}/auth/refresh",
                    json={"refreshToken": refresh_token},
                )
                if resp.status != 200:
                    logger.info(
                        "Token refresh failed (status %d), continuing without auth",
                        resp.status,
                    )
                    return None

                data = await resp.json()
                access_token = data.get("accessToken")
                new_refresh_token = data.get("refreshToken")
                plan = data.get("plan") or _extract_plan_from_jwt(access_token)

                if not access_token:
                    return None

                # Store new refresh token back
                if new_refresh_token:
                    _store_refresh_token(account_id, new_refresh_token)

                _cached_context = AuthContext(
                    account_id=account_id,
                    access_token=access_token,
                    plan=plan,
                )
                return _cached_context

        except Exception as e:
            logger.warning("Auth failed (non-fatal): %s", e)
            return None


def is_authenticated() -> bool:
    """Synchronous check if there are credentials available."""
    creds = get_credentials()
    return creds is not None and "accountId" in creds


def _get_refresh_token(account_id: str) -> str | None:
    """Try keyring first, then fall back to credentials file."""
    # Try keyring (optional dependency)
    kr = _get_keyring()
    if kr:
        try:
            token = kr.get_password("iis.tools", account_id)
            if token:
                return token
        except Exception:
            pass

    # Fall back to credentials file
    creds = get_credentials()
    if creds and "refreshToken" in creds:
        return creds["refreshToken"]

    return None


def _store_refresh_token(account_id: str, token: str) -> None:
    """Store refresh token in keyring if available."""
    kr = _get_keyring()
    if kr:
        try:
            kr.set_password("iis.tools", account_id, token)
        except Exception as e:
            logger.debug("Failed to store refresh token in keyring: %s", e)


def _extract_plan_from_jwt(token: str | None) -> str:
    """Extract plan claim from JWT payload without verifying signature."""
    if not token:
        return "free"
    try:
        import base64, json as _json
        payload = token.split(".")[1]
        payload += "=" * (4 - len(payload) % 4)
        claims = _json.loads(base64.urlsafe_b64decode(payload))
        return claims.get("plan", "free")
    except Exception:
        return "free"


def _get_keyring():
    """Lazy import keyring (optional dependency)."""
    try:
        import keyring

        return keyring
    except ImportError:
        return None


def _reset_auth_cache() -> None:
    """Reset auth cache (for testing)."""
    global _cached_context, _refresh_lock
    _cached_context = None
    _refresh_lock = None
