"""OAuth helpers for QuickBooks Online.

Pure Python implementation - no Django dependencies.
Token storage is handled by the consuming application.
"""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any
from urllib.parse import urlencode

# QuickBooks OAuth endpoints
QB_AUTHORIZATION_URL = "https://appcenter.intuit.com/connect/oauth2"
QB_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
QB_REVOKE_URL = "https://developer.api.intuit.com/v2/oauth2/tokens/revoke"

# Default scopes for QuickBooks Online accounting
QB_SCOPES = ["com.intuit.quickbooks.accounting"]


@dataclass
class TokenResponse:
    """Response from token exchange or refresh."""

    access_token: str
    refresh_token: str
    access_token_expires_at: datetime
    refresh_token_expires_at: datetime
    realm_id: str | None = None

    @classmethod
    def from_intuit_response(
        cls,
        response: dict[str, Any],
        realm_id: str | None = None,
    ) -> "TokenResponse":
        """Create from Intuit OAuth response."""
        now = datetime.utcnow()
        return cls(
            access_token=response["access_token"],
            refresh_token=response["refresh_token"],
            access_token_expires_at=now + timedelta(seconds=response.get("expires_in", 3600)),
            refresh_token_expires_at=now + timedelta(seconds=response.get("x_refresh_token_expires_in", 8726400)),
            realm_id=realm_id,
        )


def build_authorization_url(
    client_id: str,
    redirect_uri: str,
    state: str,
    scopes: list[str] | None = None,
) -> str:
    """Build the QuickBooks authorization URL.

    Args:
        client_id: QuickBooks app client ID
        redirect_uri: OAuth callback URL
        state: CSRF protection token
        scopes: OAuth scopes (defaults to QB_SCOPES)

    Returns:
        Full authorization URL to redirect user to
    """
    params = {
        "client_id": client_id,
        "redirect_uri": redirect_uri,
        "response_type": "code",
        "scope": " ".join(scopes or QB_SCOPES),
        "state": state,
    }
    return f"{QB_AUTHORIZATION_URL}?{urlencode(params)}"


def exchange_code_for_tokens(
    code: str,
    client_id: str,
    client_secret: str,
    redirect_uri: str,
    realm_id: str,
    sandbox: bool = True,
) -> TokenResponse:
    """Exchange authorization code for access and refresh tokens.

    Args:
        code: Authorization code from callback
        client_id: QuickBooks app client ID
        client_secret: QuickBooks app client secret
        redirect_uri: OAuth callback URL (must match authorization request)
        realm_id: QuickBooks company ID from callback
        sandbox: Whether using sandbox environment

    Returns:
        TokenResponse with access and refresh tokens

    Raises:
        QuickBooksOAuthError: If token exchange fails
    """
    try:
        from intuitlib.client import AuthClient

        auth_client = AuthClient(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri=redirect_uri,
            environment="sandbox" if sandbox else "production",
        )

        auth_client.get_bearer_token(code, realm_id=realm_id)

        return TokenResponse(
            access_token=auth_client.access_token,
            refresh_token=auth_client.refresh_token,
            access_token_expires_at=datetime.utcnow() + timedelta(hours=1),
            refresh_token_expires_at=datetime.utcnow() + timedelta(days=100),
            realm_id=realm_id,
        )
    except ImportError as e:
        raise QuickBooksOAuthError("intuit-oauth package not installed. Install with: pip install intuit-oauth") from e
    except Exception as e:
        raise QuickBooksOAuthError(f"Failed to exchange code for tokens: {e}") from e


def refresh_access_token(
    refresh_token: str,
    client_id: str,
    client_secret: str,
    redirect_uri: str,
    sandbox: bool = True,
) -> TokenResponse:
    """Refresh an expired access token.

    Args:
        refresh_token: Current refresh token
        client_id: QuickBooks app client ID
        client_secret: QuickBooks app client secret
        redirect_uri: OAuth callback URL
        sandbox: Whether using sandbox environment

    Returns:
        TokenResponse with new access and refresh tokens

    Raises:
        QuickBooksOAuthError: If refresh fails
    """
    try:
        from intuitlib.client import AuthClient

        auth_client = AuthClient(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri=redirect_uri,
            environment="sandbox" if sandbox else "production",
        )

        auth_client.refresh(refresh_token=refresh_token)

        return TokenResponse(
            access_token=auth_client.access_token,
            refresh_token=auth_client.refresh_token,
            access_token_expires_at=datetime.utcnow() + timedelta(hours=1),
            refresh_token_expires_at=datetime.utcnow() + timedelta(days=100),
        )
    except ImportError as e:
        raise QuickBooksOAuthError("intuit-oauth package not installed. Install with: pip install intuit-oauth") from e
    except Exception as e:
        raise QuickBooksOAuthError(f"Failed to refresh access token: {e}") from e


def revoke_token(
    token: str,
    client_id: str,
    client_secret: str,
    redirect_uri: str,
    sandbox: bool = True,
) -> bool:
    """Revoke a refresh token.

    Args:
        token: Refresh token to revoke
        client_id: QuickBooks app client ID
        client_secret: QuickBooks app client secret
        redirect_uri: OAuth callback URL
        sandbox: Whether using sandbox environment

    Returns:
        True if revocation succeeded

    Raises:
        QuickBooksOAuthError: If revocation fails
    """
    try:
        from intuitlib.client import AuthClient

        auth_client = AuthClient(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri=redirect_uri,
            environment="sandbox" if sandbox else "production",
        )

        auth_client.revoke(token=token)
        return True
    except ImportError as e:
        raise QuickBooksOAuthError("intuit-oauth package not installed. Install with: pip install intuit-oauth") from e
    except Exception as e:
        raise QuickBooksOAuthError(f"Failed to revoke token: {e}") from e


class QuickBooksOAuthError(Exception):
    """Raised when OAuth operations fail."""

    pass
