"""{{ display_name }} MCP server — generated by mcpify. Do not hand-edit.

Interactive setup wizard (REQ-1.6): collects the API URL and the
credentials the discovered auth scheme(s) need, then persists them per
the operator's choice: a .env file, a config.json file, or a ready-to-run
CLI invocation printed to stdout (nothing written to disk). `questionary`
prompts are `asyncio`-native (`.ask_async()`), unlike v2's `inquire`,
which needs `spawn_blocking`.
"""

from __future__ import annotations

import json
from pathlib import Path

import httpx
import questionary

from ..auth.auth_manager import header_location_for
from ..core.config import AuthMethod, Transport
from ..core.credential_storage import save_credential


def _to_env_key(key: str) -> str:
    return key.upper()


async def _prompt_base_url() -> str:
    url = await questionary.text("{{ display_name }} base URL:").ask_async()

    try:
        async with httpx.AsyncClient(timeout=5) as client:
            await client.head(url)
        print("reachable")
    except httpx.HTTPError:
        print(
            "could not reach that URL yet — continuing anyway "
            "(fix it later with `test-connection`)"
        )

    return url


async def _prompt_auth_method() -> AuthMethod:
{%- if auth_methods | length == 1 %}
    # Exactly one scheme was discovered — nothing to choose between.
    return AuthMethod.{{ auth_methods.0.class_name | upper }}
{%- else %}
    choices = [{% for method in auth_methods %}"{{ method.key }}"{% if not loop.last %}, {% endif %}{% endfor %}]
    selection = await questionary.select("Authentication method:", choices).ask_async()
    return AuthMethod(selection)
{%- endif %}


async def _prompt_transport() -> Transport:
    choices = [
        "stdio (spawned as a subprocess by the MCP client)",
        "http (a standalone server the MCP client connects to over the network)",
    ]
    selection = await questionary.select("Which transport will this deployment use?", choices).ask_async()
    return Transport.STDIO if selection.startswith("stdio") else Transport.HTTP


# mcpify:versions:begin
async def _prompt_api_version() -> str:
{%- if version_entries | length == 1 %}
    # Only one version is available — nothing to choose between.
    return "{{ version_entries.0.label }}"
{%- else %}
    choices = [
    {%- for v in version_entries %}
        "{{ v.label }}{% if v.label == default_version_label %} (default/latest){% endif %}",
    {%- endfor %}
    ]
    selection = await questionary.select("API version to use:", choices).ask_async()
    return selection.split(" ")[0]
{%- endif %}
# mcpify:versions:end


async def _prompt_credentials(auth_method: AuthMethod) -> dict[str, str]:
    credentials: dict[str, str] = {}
{%- if "basic" in auth_method_keys %}
    if auth_method is AuthMethod.BASIC:
        credentials["username"] = await questionary.text("Username:").ask_async()
        credentials["password"] = await questionary.password("Password:").ask_async()
{%- endif %}
{%- if "pat" in auth_method_keys %}
    if auth_method is AuthMethod.PAT:
        credentials["token"] = await questionary.password("Personal access token:").ask_async()
{%- endif %}
{%- if "apiKey" in auth_method_keys %}
    if auth_method is AuthMethod.APIKEY:
        credentials["api_key"] = await questionary.password("API key:").ask_async()
{%- endif %}
{%- if "oauth2" in auth_method_keys %}
    if auth_method is AuthMethod.OAUTH2:
        credentials["client_id"] = await questionary.text("OAuth2 client ID:").ask_async()
        client_secret = await questionary.password(
            "OAuth2 client secret (leave blank if none):"
        ).ask_async()
        if client_secret:
            credentials["client_secret"] = client_secret
        credentials["token_url"] = await questionary.text("OAuth2 token URL:").ask_async()
        authorization_code = await questionary.text(
            "Authorization code, if you already have one (leave blank to skip):"
        ).ask_async()
        if authorization_code:
            credentials["authorization_code"] = authorization_code
{%- endif %}
{%- if "oauth1" in auth_method_keys %}
    if auth_method is AuthMethod.OAUTH1:
        credentials["consumer_key"] = await questionary.text("OAuth1 consumer key:").ask_async()
        private_key_path = await questionary.text("Path to RSA private key file:").ask_async()
        credentials["private_key"] = Path(private_key_path).read_text()
{%- endif %}
    return credentials


async def _prompt_persistence(env: dict[str, str]) -> None:
    choices = [
        "Write a .env file",
        "Write a config.json file",
        "Print a ready-to-run CLI invocation (nothing written to disk)",
    ]
    selection = await questionary.select("How should these settings be saved?", choices).ask_async()

    if selection == "Write a .env file":
        contents = "\n".join(f"{key}={value}" for key, value in env.items())
        Path(".env").write_text(f"{contents}\n")
        print("Wrote .env")
    elif selection == "Write a config.json file":
        Path("config.json").write_text(json.dumps(env, indent=2))
        print("Wrote config.json")
    else:
        flags = " ".join(
            f"--{key.lower().replace('_', '-')} {value!r}" for key, value in env.items()
        )
        print(f"{{ project_name }} start {flags}")


def _print_mcp_client_config(transport: Transport, auth_method: AuthMethod, env: dict[str, str]) -> None:
    """Prints a ready-to-use MCP client config (the `mcpServers` block a
    host like Claude Code/Desktop expects) for whichever transport was
    selected — the stdio and http shapes are mutually exclusive, never
    both, since they're two different ways of running this same server
    and a client only ever picks one. HTTP transport shows credentials as
    headers only (never env/CLI args, matching
    `AuthManager.apply_auth_headers`'s HTTP-only-uses-per-request-
    credentials behavior); stdio shows both the `env` block and the
    equivalent all-CLI-args invocation, since the config cascade accepts
    either for a spawned subprocess.
    """
    if transport is Transport.STDIO:
        config = {
            "mcpServers": {
                "{{ project_name }}": {
                    "command": "{{ project_name }}",
                    "args": ["start"],
                    "env": env,
                }
            }
        }
        print("\nMCP client config (stdio):")
        print(json.dumps(config, indent=2))
        cli_args = " ".join(
            f"--{key.lower().replace('_', '-')} {value!r}" for key, value in env.items()
        )
        print(f"(equivalently: `{{ project_name }} start {cli_args}`)")
        return

    {%- if "oauth1" in auth_method_keys %}
    if auth_method is AuthMethod.OAUTH1:
        print(
            "\nOAuth1 is not supported over HTTP transport: its signature must be "
            "recomputed per request against the destination URL using the server's "
            "consumer key/secret, which a simple incoming-header relay cannot "
            "provide. Use stdio transport for this API instead."
        )
        return
    {%- endif %}
    _, header_name = header_location_for(auth_method)
    config = {
        "mcpServers": {
            "{{ project_name }}": {
                "url": "http://127.0.0.1:3000/mcp",
                "headers": {header_name: "<credential value here>"},
            }
        }
    }
    print("\nMCP client config (http) — adjust the host/port to match how you run `{{ project_name }} http`:")
    print(json.dumps(config, indent=2))
    print(
        f'Credentials are never read from local config/env over HTTP transport — '
        f'every request must carry its own "{header_name}" header.'
    )


async def run_setup_wizard() -> None:
    url = await _prompt_base_url()
    auth_method = await _prompt_auth_method()
    credentials = await _prompt_credentials(auth_method)
    api_version = await _prompt_api_version()
    transport = await _prompt_transport()

    save_credential("active-credentials", json.dumps(credentials))

    env: dict[str, str] = {
        "{{ tool_prefix_env }}_URL": url,
        "{{ tool_prefix_env }}_AUTH_METHOD": auth_method.value,
        "{{ tool_prefix_env }}_API_VERSION": api_version,
        "{{ tool_prefix_env }}_TRANSPORT": transport.value,
    }
    for key, value in credentials.items():
        env[f"{{ tool_prefix_env }}_{_to_env_key(key)}"] = value

    await _prompt_persistence(env)
    _print_mcp_client_config(transport, auth_method, env)

    run_command = "start" if transport is Transport.STDIO else "http"
    print(f"Setup complete! Run: {{ project_name }} {run_command}")
