from __future__ import annotations

from typing import Any, Dict, Iterable, List

from g_gremlin.credentials.models import INTEGRATION_REGISTRY


_DISPLAY_NAMES: dict[str, str] = {
    "apollo": "Apollo",
    "clearbit": "Clearbit",
    "google": "Google",
    "hubspot": "HubSpot",
    "looker": "Looker",
    "nimbleway": "Nimbleway",
    "outline": "Outline",
    "outreach": "Outreach",
    "pdl": "People Data Labs",
    "salesforce": "Salesforce",
    "tableau": "Tableau Cloud",
    "zendesk": "Zendesk",
    "zoominfo": "ZoomInfo",
}


def _display_name(integration: str) -> str:
    return _DISPLAY_NAMES.get(integration, str(integration or "").replace("_", " ").title())


def _manual_key_commands(integration: str) -> list[str]:
    spec = INTEGRATION_REGISTRY.get(integration)
    if spec is None:
        return []
    return [
        f"g-gremlin auth set {integration} --key {key} --value ..."
        for key in spec.required_keys
    ]


def _required_keys(integration: str) -> list[str]:
    spec = INTEGRATION_REGISTRY.get(integration)
    if spec is None:
        return []
    return list(spec.required_keys)


def _env_var_prefix(integration: str) -> str | None:
    spec = INTEGRATION_REGISTRY.get(integration)
    if spec is None:
        return None
    return spec.env_var_prefix


_AUTH_TEMPLATES: dict[str, dict[str, Any]] = {
    "apollo": {
        "integration": "apollo",
        "display_name": "Apollo",
        "surface": "runtime",
        "auth_model": "direct_api_key",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin auth set apollo --key api_key --value ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin enrich-doctor --format json",
        ],
        "explain_commands": [],
        "notes": [
            "This is direct Apollo API-key auth used by enrichment flows.",
            "It is separate from `g-gremlin apollo auth`, which authenticates the FoundryOps bridge.",
        ],
    },
    "apollo_bridge": {
        "integration": "apollo",
        "display_name": "Apollo FoundryOps bridge",
        "surface": "bridge",
        "auth_model": "foundryops_bridge",
        "precedence_summary": "explicit auth token -> env auth token -> explicit api key -> env api key -> license JWT -> dev token",
        "preferred_setup_commands": [
            "g-gremlin auth login",
        ],
        "fallback_setup_commands": [
            "g-gremlin apollo auth --workspace-id ... --api-base ...",
        ],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin apollo doctor",
        ],
        "explain_commands": [
            "g-gremlin auth explain apollo --surface bridge --json",
        ],
        "notes": [
            "Bridge auth is to FoundryOps, not Apollo directly.",
            "A workspace ID is required for `g-gremlin apollo auth`.",
        ],
    },
    "clearbit": {
        "integration": "clearbit",
        "display_name": "Clearbit",
        "surface": "runtime",
        "auth_model": "direct_api_key",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin auth set clearbit --key api_key --value ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin enrich-doctor --format json",
        ],
        "explain_commands": [],
        "notes": [],
    },
    "google": {
        "integration": "google",
        "display_name": "Google",
        "surface": "runtime",
        "auth_model": "oauth_profile",
        "precedence_summary": "active Google profile -> stored refresh token for that profile",
        "preferred_setup_commands": [
            "g-gremlin google auth connect",
            "g-gremlin google auth use <profile>",
        ],
        "fallback_setup_commands": [
            "g-gremlin google generate-ci-token",
        ],
        "status_commands": [
            "g-gremlin google auth status",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin doctor --format json",
        ],
        "explain_commands": [],
        "notes": [
            "Google auth is profile-based rather than per-integration keychain state.",
        ],
    },
    "hubspot": {
        "integration": "hubspot",
        "display_name": "HubSpot",
        "surface": "runtime",
        "auth_model": "oauth_or_pat",
        "precedence_summary": "active HubSpot profile -> stored token/PAT for that profile",
        "preferred_setup_commands": [
            "g-gremlin hubspot oauth connect",
        ],
        "fallback_setup_commands": [
            "g-gremlin hubspot connect",
        ],
        "status_commands": [
            "g-gremlin hubspot validate",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin hubspot doctor --json",
        ],
        "explain_commands": [],
        "notes": [
            "OAuth is the recommended onboarding path; PAT auth remains an advanced fallback.",
        ],
    },
    "hubspot_bridge": {
        "integration": "hubspot",
        "display_name": "HubSpot FoundryOps bridge",
        "surface": "bridge",
        "auth_model": "foundryops_bridge",
        "precedence_summary": "explicit auth token -> env auth token -> explicit api key -> env api key -> license JWT -> dev token",
        "preferred_setup_commands": [
            "g-gremlin auth login",
        ],
        "fallback_setup_commands": [
            "g-gremlin hubspot oauth connect --auth-token ...",
            "g-gremlin hubspot oauth connect --api-key ...",
        ],
        "status_commands": [
            "g-gremlin hubspot oauth status",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin hubspot doctor --json",
        ],
        "explain_commands": [
            "g-gremlin auth explain hubspot --surface bridge --json",
        ],
        "notes": [
            "This bridge flow establishes a server-managed HubSpot OAuth session.",
        ],
    },
    "looker": {
        "integration": "looker",
        "display_name": "Looker",
        "surface": "runtime",
        "auth_model": "api3_credentials",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin looker connect --base-url ... --client-id ... --client-secret ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin looker doctor --json",
        ],
        "explain_commands": [],
        "notes": [],
    },
    "nimbleway": {
        "integration": "nimbleway",
        "display_name": "Nimbleway",
        "surface": "runtime",
        "auth_model": "direct_api_key",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin auth set nimbleway --key api_key --value ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin nimbleway doctor --json",
        ],
        "explain_commands": [],
        "notes": [],
    },
    "outline": {
        "integration": "outline",
        "display_name": "Outline",
        "surface": "runtime",
        "auth_model": "direct_api_key",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin auth set outline --key api_key --value ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [],
        "explain_commands": [],
        "notes": [],
    },
    "outreach": {
        "integration": "outreach",
        "display_name": "Outreach",
        "surface": "runtime",
        "auth_model": "server_oauth_or_manual_oauth",
        "precedence_summary": "explicit runtime args -> server session -> provider/env/keychain -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin outreach oauth connect",
        ],
        "fallback_setup_commands": [
            "g-gremlin auth set outreach --key client_id --value ...",
            "g-gremlin auth set outreach --key client_secret --value ...",
            "g-gremlin auth set outreach --key refresh_token --value ...",
        ],
        "status_commands": [
            "g-gremlin outreach oauth status",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin outreach doctor --json",
        ],
        "explain_commands": [
            "g-gremlin auth explain outreach --surface runtime --json",
        ],
        "notes": [
            "Server-managed OAuth is preferred and wins over stale local credentials when both exist.",
        ],
    },
    "outreach_bridge": {
        "integration": "outreach",
        "display_name": "Outreach FoundryOps bridge",
        "surface": "bridge",
        "auth_model": "foundryops_bridge",
        "precedence_summary": "explicit auth token -> env auth token -> explicit api key -> env api key -> license JWT -> dev token",
        "preferred_setup_commands": [
            "g-gremlin auth login",
        ],
        "fallback_setup_commands": [
            "g-gremlin outreach oauth connect --auth-token ...",
            "g-gremlin outreach oauth connect --api-key ...",
        ],
        "status_commands": [
            "g-gremlin auth status",
            "g-gremlin outreach oauth status",
        ],
        "doctor_commands": [
            "g-gremlin outreach doctor --json",
        ],
        "explain_commands": [
            "g-gremlin auth explain outreach --surface bridge --json",
        ],
        "notes": [
            "This auth surface is only for bootstrapping the browser OAuth flow through FoundryOps.",
            "A successful connect stores the runtime session server-side for later Outreach commands.",
        ],
    },
    "pdl": {
        "integration": "pdl",
        "display_name": "People Data Labs",
        "surface": "runtime",
        "auth_model": "direct_api_key",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin auth set pdl --key api_key --value ...",
        ],
        "fallback_setup_commands": [],
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin enrich-doctor --format json",
        ],
        "explain_commands": [],
        "notes": [],
    },
    "salesforce": {
        "integration": "salesforce",
        "display_name": "Salesforce",
        "surface": "runtime",
        "auth_model": "sf_cli_session",
        "precedence_summary": "configured org alias -> stored sf CLI session / local alias metadata",
        "preferred_setup_commands": [
            "g-gremlin sfdc connect",
        ],
        "fallback_setup_commands": _manual_key_commands("salesforce"),
        "status_commands": [
            "g-gremlin sfdc whoami",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin sfdc doctor --json",
        ],
        "explain_commands": [],
        "notes": [
            "Prefer `sfdc connect`; manual keychain entries are mainly for compatibility and automation.",
        ],
    },
    "tableau": {
        "integration": "tableau",
        "display_name": "Tableau Cloud",
        "surface": "runtime",
        "auth_model": "pat_credentials",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin tableau auth connect",
        ],
        "fallback_setup_commands": _manual_key_commands("tableau"),
        "status_commands": [
            "g-gremlin tableau auth test",
            "g-gremlin auth status",
        ],
        "doctor_commands": [
            "g-gremlin tableau doctor --json",
        ],
        "explain_commands": [],
        "notes": [],
    },
    "zendesk": {
        "integration": "zendesk",
        "display_name": "Zendesk",
        "surface": "runtime",
        "auth_model": "api_token",
        "precedence_summary": "explicit command args -> env/keychain provider -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin zendesk connect",
        ],
        "fallback_setup_commands": _manual_key_commands("zendesk"),
        "status_commands": [
            "g-gremlin auth status",
        ],
        "doctor_commands": [],
        "explain_commands": [],
        "notes": [],
    },
    "zoominfo_runtime": {
        "integration": "zoominfo",
        "display_name": "ZoomInfo",
        "surface": "runtime",
        "auth_model": "server_oauth_or_manual_oauth",
        "precedence_summary": "explicit runtime args -> server session -> provider/env/keychain -> legacy file",
        "preferred_setup_commands": [
            "g-gremlin zoominfo oauth connect",
        ],
        "fallback_setup_commands": [
            "g-gremlin auth set zoominfo --key client_id --value ...",
            "g-gremlin auth set zoominfo --key client_secret --value ...",
        ],
        "status_commands": [
            "g-gremlin zoominfo oauth status",
            "g-gremlin auth status",
        ],
        "doctor_commands": [],
        "explain_commands": [
            "g-gremlin auth explain zoominfo --surface runtime --json",
        ],
        "notes": [
            "Server-managed OAuth is preferred and wins over stale local credentials when both exist.",
        ],
    },
    "zoominfo_bridge": {
        "integration": "zoominfo",
        "display_name": "ZoomInfo FoundryOps bridge",
        "surface": "bridge",
        "auth_model": "foundryops_bridge",
        "precedence_summary": "explicit auth token -> env auth token -> explicit api key -> env api key -> license JWT -> dev token",
        "preferred_setup_commands": [
            "g-gremlin auth login",
        ],
        "fallback_setup_commands": [
            "g-gremlin zoominfo oauth connect --auth-token ...",
            "g-gremlin zoominfo oauth connect --api-key ...",
        ],
        "status_commands": [
            "g-gremlin auth status",
            "g-gremlin zoominfo oauth status",
        ],
        "doctor_commands": [],
        "explain_commands": [
            "g-gremlin auth explain zoominfo --surface bridge --json",
        ],
        "notes": [
            "This auth surface is only for bootstrapping the browser OAuth flow through FoundryOps.",
            "A successful connect stores the runtime session server-side for later ZoomInfo commands.",
        ],
    },
}


def _enrich_template(template: dict[str, Any]) -> dict[str, Any]:
    integration = template["integration"]
    entry = dict(template)
    entry["required_keys"] = _required_keys(integration)
    entry["manual_key_commands"] = _manual_key_commands(integration)
    entry["env_var_prefix"] = _env_var_prefix(integration)
    return entry


def _dedupe(items: Iterable[str]) -> list[str]:
    seen: set[str] = set()
    ordered: list[str] = []
    for item in items:
        if item not in seen:
            seen.add(item)
            ordered.append(item)
    return ordered


def _resolve_tokens(command_id: str, requires_auth: list[str]) -> list[str]:
    command_id = str(command_id or "").strip().lower()
    tokens: list[str] = []

    if command_id.startswith("zoominfo:oauth:"):
        tokens.append("zoominfo_bridge")
    elif command_id.startswith("zoominfo:"):
        tokens.append("zoominfo_runtime")

    if command_id.startswith("outreach:oauth:"):
        tokens.append("outreach_bridge")

    if command_id.startswith("hubspot:oauth:"):
        tokens.append("hubspot_bridge")

    if command_id.startswith("apollo:"):
        tokens.append("apollo_bridge")

    for integration in requires_auth:
        if integration == "apollo" and command_id.startswith("apollo:"):
            continue
        if integration == "outreach" and command_id.startswith("outreach:oauth:"):
            continue
        tokens.append(integration)

    return _dedupe(tokens)


def resolve_command_auth(command_id: str, requires_auth: list[str] | None) -> dict[str, Any]:
    integrations: list[dict[str, Any]] = []
    for token in _resolve_tokens(command_id, list(requires_auth or [])):
        template = _AUTH_TEMPLATES.get(token)
        if template is None:
            continue
        integrations.append(_enrich_template(template))

    return {
        "required": bool(integrations),
        "integrations": integrations,
    }
