"""Telemetry management commands.

Subcommands:
  enable / disable / status — CLI analytics opt-in/out (PostHog)
  setup                     — Enable runtime observability (OTLP traces/logs)
  observability-status      — Check observability status
  observability-disable     — Disable runtime observability
"""

import json
import os
import sys
from pathlib import Path

import typer

from rich.syntax import Syntax

from nogic.config import GLOBAL_CONFIG_DIR, CONFIG_FILE, Config, is_dev_mode, get_api_url
from nogic.api.client import NogicClient
from nogic import telemetry, ui

telemetry_app = typer.Typer(no_args_is_help=True, rich_markup_mode="rich")


# =============================================================================
# Helpers
# =============================================================================


def _load_global_config() -> dict:
    config_path = GLOBAL_CONFIG_DIR / CONFIG_FILE
    if config_path.exists():
        try:
            with open(config_path, encoding="utf-8") as f:
                return json.load(f)
        except (json.JSONDecodeError, OSError):
            return {}
    return {}


def _save_global_config(data: dict):
    GLOBAL_CONFIG_DIR.mkdir(mode=0o700, exist_ok=True)
    config_path = GLOBAL_CONFIG_DIR / CONFIG_FILE
    with open(config_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2)
    os.chmod(config_path, 0o600)


def _require_project() -> tuple[Config, NogicClient]:
    """Load config and verify project is initialized."""
    config = Config.load()
    if not config.api_key:
        ui.error("Not logged in. Run `nogic login` first.")
        raise typer.Exit(1)
    if not config.project_id:
        ui.error("No project initialized. Run `nogic init` first.")
        raise typer.Exit(1)
    return config, NogicClient(config)


def _detect_language(directory: Path | None = None) -> str | None:
    """Detect primary language from project files."""
    if directory is None:
        directory = Path.cwd()
    checks = [
        ("tsconfig.json", "typescript"),
        ("package.json", "javascript"),
        ("pyproject.toml", "python"),
        ("requirements.txt", "python"),
        ("setup.py", "python"),
        ("go.mod", "go"),
        ("Cargo.toml", "rust"),
        ("Gemfile", "ruby"),
        ("pom.xml", "java"),
        ("build.gradle", "java"),
    ]
    for filename, lang in checks:
        if (directory / filename).exists():
            return lang
    return None


_SDK_SNIPPETS = {
    "python": {
        "install": "pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http",
        "code": '''\
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

provider = TracerProvider()
exporter = OTLPSpanExporter(
    endpoint="{endpoint}/v1/traces",
    headers={{"x-api-key": "{key}"}},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("my-operation"):
    # your code here
    pass''',
    },
    "javascript": {
        "install": "npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http",
        "code": '''\
const {{ NodeSDK }} = require("@opentelemetry/sdk-node");
const {{ OTLPTraceExporter }} = require("@opentelemetry/exporter-trace-otlp-http");

const sdk = new NodeSDK({{
  traceExporter: new OTLPTraceExporter({{
    url: "{endpoint}/v1/traces",
    headers: {{ "x-api-key": "{key}" }},
  }}),
}});
sdk.start();''',
    },
    "typescript": {
        "install": "npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http",
        "code": '''\
import {{ NodeSDK }} from "@opentelemetry/sdk-node";
import {{ OTLPTraceExporter }} from "@opentelemetry/exporter-trace-otlp-http";

const sdk = new NodeSDK({{
  traceExporter: new OTLPTraceExporter({{
    url: "{endpoint}/v1/traces",
    headers: {{ "x-api-key": "{key}" }},
  }}),
}});
sdk.start();''',
    },
    "go": {
        "install": 'go get go.opentelemetry.io/otel go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp',
        "code": '''\
import (
    "context"
    "log"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

ctx := context.Background()
exporter, err := otlptracehttp.New(ctx,
    otlptracehttp.WithEndpoint("{endpoint_host}"),
    otlptracehttp.WithURLPath("/v1/traces"),
    otlptracehttp.WithHeaders(map[string]string{{"x-api-key": "{key}"}}),
)
if err != nil {{
    log.Fatal(err)
}}
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(tp)''',
    },
}


# =============================================================================
# CLI Analytics Commands (PostHog opt-in/out)
# =============================================================================


@telemetry_app.command("status")
def telemetry_status():
    """Show current CLI analytics status."""
    config = _load_global_config()
    enabled = config.get("telemetry_enabled", True) is not False

    if enabled:
        ui.success("CLI analytics is enabled")
        ui.dim("  Run `nogic telemetry disable` to opt out")
    else:
        ui.warn("CLI analytics is disabled")
        ui.dim("  Run `nogic telemetry enable` to enable")

    ui.console.print()
    ui.dim("Analytics helps us improve Nogic. All data is anonymized.")


@telemetry_app.command("enable")
def telemetry_enable():
    """Enable CLI analytics."""
    config = _load_global_config()
    config["telemetry_enabled"] = True
    _save_global_config(config)
    ui.success("CLI analytics enabled")


@telemetry_app.command("disable")
def telemetry_disable():
    """Disable CLI analytics."""
    config = _load_global_config()
    config["telemetry_enabled"] = False
    _save_global_config(config)
    ui.success("CLI analytics disabled")


# =============================================================================
# Runtime Observability Commands (OTLP traces/logs)
# =============================================================================


@telemetry_app.command("setup")
def observability_setup(
    output_json: bool = typer.Option(False, "--json", help="Output as JSON (for extension integration)."),
):
    """Set up runtime observability for this project.

    Enables OTLP trace/log collection and creates an ingest key.
    Shows language-specific SDK setup instructions.
    """
    config, client = _require_project()

    if is_dev_mode():
        ui.dev_banner(get_api_url())

    try:
        with ui.status_spinner("Setting up telemetry..."):
            result = client.setup_telemetry(config.project_id)
    except Exception as e:
        ui.error(f"Failed to set up telemetry: {e}")
        raise typer.Exit(1)
    finally:
        client.close()

    # Validate required fields in API response
    try:
        enabled = result["enabled"]
        endpoint = result["endpoint"]
        project_id = result["project_id"]
    except KeyError as e:
        ui.error(f"Unexpected API response: missing {e}")
        raise typer.Exit(1)

    if output_json:
        # JSON output for extension integration
        lang = _detect_language()
        output = {
            "enabled": enabled,
            "endpoint": endpoint,
            "project_id": project_id,
            "key_prefix": result.get("key_prefix"),
            "language": lang,
        }
        if result.get("ingest_key"):
            output["ingest_key"] = result["ingest_key"]
        if lang and lang in _SDK_SNIPPETS:
            key_placeholder = result.get("ingest_key") or result.get("key_prefix") or "nogic_sk_..."
            snippets = _SDK_SNIPPETS[lang]
            output["install_command"] = snippets["install"]
            output["setup_code"] = snippets["code"].format(
                endpoint=endpoint,
                endpoint_host=endpoint.replace("https://", "").replace("http://", ""),
                key=key_placeholder,
            )
        json.dump(output, sys.stdout)
        sys.stdout.write("\n")
        telemetry.capture("cli_telemetry_setup", {"language": lang, "has_key": bool(result.get("ingest_key"))})
        return

    ui.console.print()
    ui.banner("nogic telemetry setup")

    if result.get("ingest_key"):
        ui.success("Telemetry enabled — new ingest key created")
        ui.console.print()
        ui.kv("Ingest Key", f"[bold]{result['ingest_key']}[/]")
        ui.console.print()
        ui.warn("Save this key now — it won't be shown again.")
    else:
        ui.success("Telemetry is already enabled")
        ui.console.print()
        ui.kv("Key Prefix", result.get("key_prefix", ""))

    ui.kv("Endpoint", endpoint)
    ui.kv("Project ID", project_id)

    # Language detection + SDK snippets
    lang = _detect_language()
    if lang and lang in _SDK_SNIPPETS:
        key = result.get("ingest_key") or f"{result.get('key_prefix') or 'nogic_sk_'}..."
        snippets = _SDK_SNIPPETS[lang]

        ui.console.print()
        ui.section(f"SDK Setup ({lang})")
        ui.console.print()
        ui.info("Install dependencies:")
        ui.console.print(f"\n  [bold]{snippets['install']}[/]\n")
        ui.info("Add to your app:")
        code = snippets["code"].format(
            endpoint=endpoint,
            endpoint_host=endpoint.replace("https://", "").replace("http://", ""),
            key=key,
        )
        syntax = Syntax(code, lang if lang != "typescript" else "javascript", padding=1)
        ui.console.print(syntax)
    elif lang:
        ui.console.print()
        ui.dim(f"  Detected language: {lang} (no SDK snippet available yet)")
        ui.dim(f"  Use any OTLP-compatible SDK with endpoint: {endpoint}")

    ui.console.print()
    ui.dim("  Once instrumented, use MCP telemetry tools to query your data.")

    telemetry.capture("cli_telemetry_setup", {"language": lang, "has_key": bool(result.get("ingest_key"))})


@telemetry_app.command("observability-status")
def observability_status():
    """Check runtime observability status for this project."""
    config, client = _require_project()

    if is_dev_mode():
        ui.dev_banner(get_api_url())

    try:
        with ui.status_spinner("Checking telemetry status..."):
            result = client.get_telemetry_status(config.project_id)
    except Exception as e:
        ui.error(f"Failed to check telemetry status: {e}")
        raise typer.Exit(1)
    finally:
        client.close()

    try:
        enabled = result["enabled"]
        has_key = result["has_ingest_key"]
        endpoint = result["endpoint"]
    except KeyError as e:
        ui.error(f"Unexpected API response: missing {e}")
        raise typer.Exit(1)

    ui.console.print()
    if enabled:
        ui.success("Runtime observability is enabled")
        ui.kv("Key Prefix", result.get("key_prefix", "none") if has_key else "none")
        ui.kv("Endpoint", endpoint)
    else:
        ui.info("Runtime observability is not enabled")
        ui.dim("  Run `nogic telemetry setup` to enable it")


@telemetry_app.command("observability-disable")
def observability_disable():
    """Disable runtime observability for this project."""
    config, client = _require_project()

    if is_dev_mode():
        ui.dev_banner(get_api_url())

    try:
        client.disable_telemetry(config.project_id)
    except Exception as e:
        ui.error(f"Failed to disable telemetry: {e}")
        raise typer.Exit(1)
    finally:
        client.close()

    ui.console.print()
    ui.success("Runtime observability disabled")
    ui.dim("  Ingest keys are not revoked — manage them with `nogic keys`")

    telemetry.capture("cli_telemetry_disable", {"success": True})
