from __future__ import annotations

import os
import uuid
from datetime import datetime, timedelta, timezone
from typing import Any

from fastapi import HTTPException
from jose import jwt
from jose.exceptions import JWTError

INSTALL_TOKEN_AUDIENCE = "g-gremlin-install"
_CLI_PLAN_ORDER = {"community", "pro", "crm_engineer", "platform", "enterprise"}


def install_token_secret(*, required: bool) -> str | None:
    secret = os.getenv("AGENT_INSTALL_TOKEN_SECRET", "").strip()
    if secret:
        return secret
    if required:
        raise HTTPException(
            status_code=503,
            detail=(
                "Install token resolver is not configured. "
                "Set AGENT_INSTALL_TOKEN_SECRET or use G_GREMLIN_LICENSE_INSTALL_TOKEN_MAP for dev."
            ),
        )
    return None


def install_token_issuer() -> str:
    return os.getenv("G_GREMLIN_INSTALL_TOKEN_ISSUER", "foundryops").strip() or "foundryops"


def gremlin_cli_plan_for_state(plan_key: Any) -> str:
    normalized = str(plan_key or "").strip().lower()
    if not normalized:
        return "community"
    if normalized in _CLI_PLAN_ORDER:
        return normalized

    legacy_map = {
        "local_free": "community",
        "free": "community",
        "agent_free": "community",
        "workspace_ops": "pro",
        "hubspot_admin": "crm_engineer",
        "full_stack": "platform",
        "unleashed": "platform",
        "scale": "platform",
        "paid": "platform",
        "agent_paid": "platform",
    }
    return legacy_map.get(normalized, "platform")


def issue_local_install_token(
    *,
    account_id: str,
    clerk_user_id: str | None,
    primary_email: str | None,
    product_surface: str,
    expires_in_hours: int,
    single_use: bool,
) -> dict[str, Any]:
    secret = install_token_secret(required=True)
    now = datetime.now(timezone.utc)
    expires_at = now + timedelta(hours=max(1, int(expires_in_hours)))
    payload = {
        "iss": install_token_issuer(),
        "aud": INSTALL_TOKEN_AUDIENCE,
        "iat": int(now.timestamp()),
        "nbf": int(now.timestamp()),
        "exp": int(expires_at.timestamp()),
        "jti": f"itok_{uuid.uuid4().hex}",
        "token_type": "install_token",
        "product_surface": (product_surface or "gremlin").strip().lower() or "gremlin",
        "account_id": account_id,
        "clerk_user_id": (clerk_user_id or "").strip() or None,
        "primary_email": (primary_email or "").strip().lower() or None,
        "single_use": bool(single_use),
    }
    token = jwt.encode(payload, secret, algorithm="HS256")
    return {
        "token": token,
        "token_expires_at": expires_at.replace(microsecond=0).isoformat().replace("+00:00", "Z"),
        "single_use": bool(single_use),
    }


def try_decode_local_install_token(token: str) -> dict[str, Any] | None:
    secret = install_token_secret(required=False)
    if not secret:
        return None

    decode_attempts = (
        {
            "audience": INSTALL_TOKEN_AUDIENCE,
            "issuer": install_token_issuer(),
            "options": None,
        },
        {
            "audience": None,
            "issuer": None,
            "options": {"verify_aud": False, "verify_iss": False},
        },
    )

    for attempt in decode_attempts:
        try:
            kwargs: dict[str, Any] = {
                "key": secret,
                "algorithms": ["HS256"],
            }
            if attempt["audience"] is not None:
                kwargs["audience"] = attempt["audience"]
            if attempt["issuer"] is not None:
                kwargs["issuer"] = attempt["issuer"]
            if attempt["options"] is not None:
                kwargs["options"] = attempt["options"]
            payload = jwt.decode(token, **kwargs)
        except JWTError:
            continue

        if not isinstance(payload, dict):
            return None
        if str(payload.get("token_type") or "").strip().lower() != "install_token":
            return None
        return payload

    return None
