"""Config subcommands: activate, deactivate, status, telemetry, corpus-delete."""

from __future__ import annotations

import asyncio
import json
import os
import shutil
import sys
from datetime import UTC, datetime
from pathlib import Path
from typing import TYPE_CHECKING, Annotated

import typer
from rich.panel import Panel

if TYPE_CHECKING:
    from complyform.cli.main import AppContext

config_app = typer.Typer(
    name="config",
    help="Manage ComplyForm configuration.",
    no_args_is_help=True,
)


@config_app.command(name="activate")
def config_activate(
    ctx: typer.Context,
    key: Annotated[
        str | None,
        typer.Argument(help="License key (cf_live_... or cf_test_...)"),
    ] = None,
    license_file: Annotated[
        str | None,
        typer.Option("--license-file", help="Path to .complyform-license file"),
    ] = None,
) -> None:
    """Activate a ComplyForm license."""
    from complyform.core.auth.license import LicenseManager, validate_license_key_format
    from complyform.core.errors import LicenseInvalidError

    app_ctx: AppContext = ctx.obj
    console = app_ctx.console

    mgr = LicenseManager()

    if license_file is not None:
        # Air-gapped activation
        path = Path(license_file)
        if not path.exists():
            raise LicenseInvalidError(f"File not found: {license_file}")

        cache = mgr.validate_airgap_license(path)
        mgr.save_cache(cache)

        exp = cache.expires_at or "never"
        console.print(
            Panel(
                f"[bold green]\u2713 License activated[/bold green]"
                f" \u2014 {cache.tier} tier (expires {exp})\n"
                f"[bold green]\u2713 Profiles downloaded[/bold green]"
                f" \u2014 frameworks available\n\n"
                "[dim]By activating, you confirm acceptance of the"
                " Terms of Service:\nhttps://complyform.dev/terms[/dim]",
                style="green",
            )
        )
        return

    if key is None:
        raise LicenseInvalidError("Provide a license key or --license-file")

    if not validate_license_key_format(key):
        raise LicenseInvalidError("Invalid key format")

    # Online activation via POST /v1/license/validate
    from complyform.core.license import activate_online

    cache = asyncio.get_event_loop().run_until_complete(activate_online(key, mgr))

    exp = cache.expires_at or "never"
    console.print(
        Panel(
            f"[bold green]\u2713 License activated[/bold green]"
            f" \u2014 {cache.tier} tier (expires {exp})\n"
            f"[bold green]\u2713 Profiles downloaded[/bold green]"
            f" \u2014 frameworks available\n\n"
            "[dim]By activating, you confirm acceptance of the"
            " Terms of Service:\nhttps://complyform.dev/terms[/dim]",
            style="green",
        )
    )


@config_app.command(name="deactivate")
def config_deactivate(ctx: typer.Context) -> None:
    """Deactivate license and revert to Community tier."""
    from complyform.core.auth.license import LicenseManager
    from complyform.core.config import save_config

    app_ctx: AppContext = ctx.obj
    console = app_ctx.console
    config = app_ctx.config

    mgr = LicenseManager()
    mgr.clear_cache()

    # Clear paid profiles and cache directories
    complyform_dir = Path.home() / ".complyform"
    cache_dir = complyform_dir / "cache"
    profiles_dir = complyform_dir / "profiles"
    if cache_dir.exists():
        shutil.rmtree(cache_dir)
    if profiles_dir.exists():
        shutil.rmtree(profiles_dir)

    # Clear license state from config, preserve user preferences
    config.license_key_hash = None
    config.tier = "community"
    config.license_expiry = None
    config.api_key = None
    save_config(config, app_ctx.config_path)

    console.print(
        Panel(
            "[bold green]\u2713 Local license cleared.[/bold green]"
            " Reverted to Community tier.\n\n"
            "[dim]Server-side features (dashboard, drift monitoring)"
            " remain active until subscription expiry.\n"
            "To cancel: https://complyform.dev/billing[/dim]",
            style="green",
        )
    )


@config_app.command(name="export-data")
def config_export_data(ctx: typer.Context) -> None:
    """Request export of all hosted data (Team+)."""
    from complyform.cli.data_cmd import export_data_cmd

    export_data_cmd(ctx)


@config_app.command(name="delete-data")
def config_delete_data(ctx: typer.Context) -> None:
    """Request deletion of all hosted data. Irreversible."""
    from complyform.cli.data_cmd import delete_data_cmd

    delete_data_cmd(ctx)


@config_app.command(name="status")
def config_status(
    ctx: typer.Context,
    verbose: Annotated[
        bool,
        typer.Option("--verbose", "-v", help="Show detailed status information"),
    ] = False,
    format: Annotated[
        str,
        typer.Option("--format", "-f", help="Output format: terminal|json"),
    ] = "terminal",
) -> None:
    """Show current tier and license status."""
    from complyform import __version__
    from complyform.core.auth.license import LicenseManager

    app_ctx: AppContext = ctx.obj
    console = app_ctx.console
    config = app_ctx.config

    mgr = LicenseManager()
    cache = mgr.load_cache()

    tier = "community"
    license_status = "Community (no license)"
    projects_info = "1 of 1 used"
    expires_at: str | None = None

    if cache is not None:
        tier = cache.tier
        expires_at = cache.expires_at
        if cache.expires_at:
            if mgr.is_within_grace_period(cache):
                license_status = f"Active (expires {cache.expires_at})"
            else:
                license_status = "Expired"
        else:
            license_status = f"Active ({tier} tier)"

        if cache.project_limit is not None:
            projects_info = f"\u2014 of {cache.project_limit} used"
        else:
            projects_info = "unlimited"

    if not verbose:
        if format == "json":
            envelope = {
                "schema_version": 1,
                "tool": "complyform",
                "tool_version": __version__,
                "command": "config status",
                "timestamp": datetime.now(tz=UTC).isoformat(),
                "result": {
                    "version": __version__,
                    "tier": tier,
                    "license_status": license_status,
                    "projects": projects_info,
                },
            }
            sys.stdout.write(json.dumps(envelope, indent=2) + "\n")
        else:
            console.print(
                f"ComplyForm v{__version__}\n"
                f"Tier: {tier}\n"
                f"License: {license_status}\n"
                f"Projects: {projects_info}"
            )
        return

    # --- Verbose output ---
    verbose_data = _build_verbose_status(
        config=config,
        cache=cache,
        tier=tier,
        license_status=license_status,
        expires_at=expires_at,
        version=__version__,
    )

    if format == "json":
        envelope = {
            "schema_version": 1,
            "tool": "complyform",
            "tool_version": __version__,
            "command": "config status",
            "timestamp": datetime.now(tz=UTC).isoformat(),
            "result": verbose_data,
        }
        sys.stdout.write(json.dumps(envelope, indent=2) + "\n")
    else:
        _render_verbose_status(console, verbose_data, __version__)


def _build_verbose_status(
    *,
    config: object,
    cache: object,
    tier: str,
    license_status: str,
    expires_at: str | None,
    version: str,
) -> dict[str, object]:
    """Build verbose status data dict."""
    from complyform.core.auth.tier_config import TIER_CONFIG
    from complyform.core.config import ComplyFormConfig

    assert isinstance(config, ComplyFormConfig)

    tier_cfg = TIER_CONFIG.get(tier, {})

    # License section
    license_info: dict[str, object] = {
        "tier": tier,
        "status": license_status,
        "expires": expires_at,
    }

    if cache is not None:
        from complyform.core.auth.license import LicenseCache

        assert isinstance(cache, LicenseCache)
        if cache.key_hash:
            license_info["key"] = cache.key_hash[:8] + "..."
        license_info["last_validated"] = cache.last_validated_at

        if expires_at:
            try:
                exp_dt = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
                days_remaining = (exp_dt - datetime.now(tz=UTC)).days
                license_info["days_remaining"] = max(0, days_remaining)
            except ValueError, TypeError:
                pass

    # Features section
    features: dict[str, object] = {}
    scan_sources = tier_cfg.get("scan_sources", [])
    feature_list = tier_cfg.get("features", [])
    features["scan_sources"] = scan_sources
    features["frameworks"] = (
        "all_53"
        if tier_cfg.get("assess_frameworks") == ["all"]
        else tier_cfg.get("assess_frameworks", [])
    )
    for feat in [
        "html_report",
        "hosted_dashboard",
        "drift_alerts",
        "opa_rego",
        "iam_analysis",
        "cross_validation",
        "cost_impact",
        "branded_pdf",
        "batch_remediate",
        "pr_remediation",
        "ai_explain",
    ]:
        feat_list = feature_list if isinstance(feature_list, list) else []
        features[feat] = feat in feat_list

    # Profiles section
    profiles_info: dict[str, object] = {}
    version_file = Path.home() / ".complyform" / "profiles" / "VERSION"
    if version_file.exists():
        ver_text = version_file.read_text(encoding="utf-8").strip()
        profiles_info["bundle_version"] = ver_text
        manifest_file = Path.home() / ".complyform" / "profiles" / "manifest.json"
        if manifest_file.exists():
            try:
                manifest = json.loads(manifest_file.read_text(encoding="utf-8"))
                profiles_info["bundle_hash"] = manifest.get("sha256", "unknown")
            except Exception:
                pass
        stat = version_file.stat()
        profiles_info["installed_at"] = datetime.fromtimestamp(
            stat.st_mtime, tz=UTC
        ).isoformat()
    else:
        profiles_info["bundle_version"] = None

    # Cloud auth section
    cloud_auth: dict[str, str] = {}
    for cloud, cmd in [
        ("gcp", ["gcloud", "config", "get-value", "project"]),
        ("aws", ["aws", "sts", "get-caller-identity"]),
        ("azure", ["az", "account", "show"]),
    ]:
        try:
            import subprocess

            result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
            if result.returncode == 0:
                if cloud == "gcp":
                    project = result.stdout.strip()
                    cloud_auth[cloud] = f"Configured (project: {project})"
                else:
                    cloud_auth[cloud] = "Configured"
            else:
                cloud_auth[cloud] = "Not configured"
        except Exception:
            cloud_auth[cloud] = "Not verified (offline)"

    # Cache section
    cache_info: dict[str, object] = {}
    cache_dir = Path.home() / ".complyform" / "cache"
    if cache_dir.exists():
        count = sum(1 for e in cache_dir.iterdir() if e.is_dir())
        total = 0
        latest: float = 0
        for entry in cache_dir.iterdir():
            if entry.is_dir():
                for f in entry.iterdir():
                    if f.is_file():
                        total += f.stat().st_size
                        latest = max(latest, f.stat().st_mtime)
        cache_info["entries"] = count
        cache_info["directory"] = str(cache_dir)
        if total < 1024 * 1024:
            cache_info["size"] = f"{total / 1024:.1f} KB"
        else:
            cache_info["size"] = f"{total / (1024 * 1024):.1f} MB"
        if latest > 0:
            cache_info["latest"] = datetime.fromtimestamp(latest, tz=UTC).strftime(
                "%Y-%m-%d"
            )
    else:
        cache_info["entries"] = 0
        cache_info["directory"] = str(cache_dir)
        cache_info["size"] = "0 B"

    return {
        "version": version,
        "license": license_info,
        "features": features,
        "profiles": profiles_info,
        "cloud_auth": cloud_auth,
        "cache": cache_info,
        "billing_url": "https://dashboard.complyform.dev/settings",
    }


def _render_verbose_status(
    console: object,
    data: dict[str, object],
    version: str,
) -> None:
    """Render verbose status to terminal."""
    from rich.console import Console

    assert isinstance(console, Console)

    console.print(f"\n[bold]ComplyForm v{version}[/bold]\n")

    # License
    lic = data.get("license", {})
    assert isinstance(lic, dict)
    console.print("[bold]License:[/bold]")
    for key, label in [
        ("tier", "Tier"),
        ("status", "Status"),
        ("key", "Key"),
        ("expires", "Expires"),
        ("days_remaining", "Days remaining"),
        ("last_validated", "Last validated"),
    ]:
        val = lic.get(key)
        if val is not None:
            console.print(f"  {label + ':':<20} {val}")
    console.print()

    # Features
    feats = data.get("features", {})
    assert isinstance(feats, dict)
    console.print("[bold]Features:[/bold]")
    for key, val in feats.items():
        display = val
        if isinstance(val, bool):
            display = "true" if val else "false"
        elif isinstance(val, list):
            display = ", ".join(str(v) for v in val) if val else "none"
        console.print(f"  {key + ':':<20} {display}")
    console.print()

    # Profiles
    prof = data.get("profiles", {})
    assert isinstance(prof, dict)
    console.print("[bold]Profiles:[/bold]")
    if prof.get("bundle_version"):
        for key, label in [
            ("bundle_version", "Bundle version"),
            ("bundle_hash", "Bundle hash"),
            ("installed_at", "Installed"),
        ]:
            val = prof.get(key)
            if val is not None:
                console.print(f"  {label + ':':<20} {val}")
    else:
        console.print("  No paid profiles installed")
    console.print()

    # Cloud Auth
    cloud = data.get("cloud_auth", {})
    assert isinstance(cloud, dict)
    console.print("[bold]Cloud Auth:[/bold]")
    for provider, status in cloud.items():
        console.print(f"  {provider.upper() + ':':<20} {status}")
    console.print()

    # Cache
    cache = data.get("cache", {})
    assert isinstance(cache, dict)
    console.print("[bold]Cache:[/bold]")
    console.print(f"  {'Scan cache:':<20} {cache.get('entries', 0)} entries")
    cache_dir_str = cache.get("directory", "~/.complyform/cache/")
    console.print(f"  {'Cache directory:':<20} {cache_dir_str}")
    console.print(f"  {'Cache size:':<20} {cache.get('size', '0 B')}")
    console.print()

    # Billing
    billing = data.get("billing_url", "")
    console.print("[bold]Billing:[/bold]")
    console.print(f"  Manage subscription: {billing}")
    console.print()


@config_app.command(name="telemetry")
def config_telemetry(
    ctx: typer.Context,
    enable: Annotated[
        bool,
        typer.Option("--enable", help="Enable telemetry"),
    ] = False,
    disable: Annotated[
        bool,
        typer.Option("--disable", help="Disable telemetry"),
    ] = False,
    info: Annotated[
        bool,
        typer.Option("--info", help="Show telemetry information"),
    ] = False,
) -> None:
    """Manage telemetry settings."""
    from complyform.core.config import save_config
    from complyform.core.errors import MutualExclusivityError

    app_ctx: AppContext = ctx.obj
    console = app_ctx.console
    config = app_ctx.config

    flag_count = sum([enable, disable, info])
    if flag_count == 0:
        # Default: show info
        info = True
    elif flag_count > 1:
        raise MutualExclusivityError(
            "Use only one of --enable, --disable, or --info.",
            "Pick one flag.",
        )

    if info:
        status = "enabled" if config.telemetry else "disabled"
        console.print(
            "[bold]Telemetry Information[/bold]\n\n"
            "ComplyForm collects anonymous usage data to improve the product:\n"
            "  - Command names and flags used (no arguments/values)\n"
            "  - Framework names assessed\n"
            "  - Error codes (no stack traces or messages)\n"
            "  - CLI version and OS platform\n\n"
            "No PII, file paths, resource names, or cloud credentials"
            " are ever collected.\n\n"
            f"Current status: [bold]{status}[/bold]\n\n"
            "Privacy policy: https://complyform.dev/privacy"
        )
        return

    if enable:
        # Check DO_NOT_TRACK
        if os.environ.get("DO_NOT_TRACK") == "1":
            console.print(
                "[yellow]DO_NOT_TRACK=1 is set in your environment."
                " Telemetry cannot be enabled while this variable"
                " is active.[/yellow]"
            )
            return

        config.telemetry = True
        save_config(config, app_ctx.config_path)
        console.print(
            "[green]\u2713 Telemetry enabled.[/green]\n"
            "Thank you for helping improve ComplyForm."
        )
        return

    if disable:
        config.telemetry = False
        config.corpus_contribution = False
        save_config(config, app_ctx.config_path)
        console.print(
            "[green]\u2713 Telemetry disabled.[/green]\n"
            "[dim]Corpus contribution has been disabled"
            " (requires telemetry).[/dim]"
        )


@config_app.command(name="corpus-delete")
def config_corpus_delete(
    ctx: typer.Context,
    confirm: Annotated[
        bool,
        typer.Option("--confirm", help="Skip confirmation prompt"),
    ] = False,
) -> None:
    """Delete all corpus contributions for this installation."""
    from complyform.core.config import save_config

    app_ctx: AppContext = ctx.obj
    console = app_ctx.console
    config = app_ctx.config

    # Check for corpus_contributor_id — it may be stored in config
    # or in a separate file. We check the config dict for it.
    config_data = config.model_dump(mode="json")
    contributor_id = config_data.get("corpus_contributor_id")

    if not contributor_id:
        console.print("No corpus contributions found for this installation.")
        raise typer.Exit(code=0)

    # Confirmation
    is_ci = os.environ.get("CI") == "true"
    if not confirm and not is_ci:
        if sys.stdin.isatty():
            console.print(
                "[yellow]This will permanently delete all corpus"
                " contributions from this installation.[/yellow]\n"
            )
            response = typer.prompt(
                "Type 'DELETE' to confirm", default="", show_default=False
            )
            if response != "DELETE":
                console.print("Cancelled.")
                raise typer.Exit(code=0)
        else:
            console.print("Use --confirm flag in non-interactive mode.")
            raise typer.Exit(code=1)

    # Send DELETE request
    try:
        import httpx

        api_base = os.environ.get("COMPLYFORM_API_BASE", "https://api.complyform.dev")
        resp = httpx.request(
            "DELETE",
            f"{api_base}/corpus/contributor",
            json={"corpus_contributor_id": contributor_id},
            timeout=10.0,
        )

        if resp.status_code == 429:
            console.print(
                "[red]Rate limited. Corpus deletion is limited"
                " to 1 request per day. Try again tomorrow.[/red]"
            )
            raise typer.Exit(code=1)

        if resp.status_code not in (200, 204):
            console.print(
                f"[red]Corpus deletion failed (HTTP {resp.status_code}).[/red]"
            )
            raise typer.Exit(code=1)

        # Reset local config
        config.corpus_contribution = False
        config.telemetry = False
        save_config(config, app_ctx.config_path)

        console.print(
            "[green]\u2713 Corpus contributions deleted.[/green]\n"
            "Telemetry and corpus contribution have been disabled."
        )

    except typer.Exit:
        raise
    except Exception as e:
        console.print(f"[red]Could not delete corpus contributions: {e}[/red]")
        raise typer.Exit(code=1) from None
