"""Dashboard CLI commands — push scan results to hosted dashboard.

Wires the ``complyform dashboard push`` subcommand that sends cached
assessment data to the ComplyForm Dashboard API.
"""

from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Annotated, Any

import typer
from rich.console import Console

from complyform.cli.main import app
from complyform.core.errors import (
    ComplyFormError,
    FeatureNotAvailableError,
    NoCachedAssessmentError,
)

_stderr = Console(stderr=True)

dashboard_app = typer.Typer(name="dashboard", help="Dashboard operations.")

_API_BASE = "https://api.complyform.dev"


def _resolve_api_key(api_key_flag: str | None) -> str:
    """Resolve API key from flag → env → config, in priority order."""
    if api_key_flag:
        return api_key_flag

    env_key = os.environ.get("COMPLYFORM_API_KEY")
    if env_key:
        return env_key

    from complyform.core.config import load_config, resolve_config_path

    config_path = resolve_config_path(None)
    cfg = load_config(config_path)
    key: str = getattr(cfg, "api_key", "")
    if key:
        return key

    raise ComplyFormError(
        title="API Key Required",
        message=(
            "No API key found. Set via --api-key, COMPLYFORM_API_KEY env, or config."
        ),
        fix="complyform config set api_key <key>",
    )


def _build_cloud_intelligence_payload(
    metadata: dict[str, Any],
) -> dict[str, Any]:
    """Extract cloud intelligence data from cache metadata for dashboard push."""
    ci: dict[str, Any] = {}

    iam = metadata.get("iam_analysis")
    if isinstance(iam, dict) and iam.get("success"):
        ci["iam_analysis"] = {
            "principals_scanned": iam.get("principals_scanned", 0),
            "over_provisioned_count": iam.get("over_provisioned_count", 0),
            "unused_role_count": iam.get("unused_role_count", 0),
        }

    xval = metadata.get("cross_validation")
    if isinstance(xval, dict) and xval.get("success"):
        ci["cross_validation"] = {
            "score": xval.get("cross_validation_score", 0),
            "confirmed_count": len(xval.get("confirmed", [])),
            "complyform_only_count": len(xval.get("complyform_only", [])),
            "native_only_count": len(xval.get("native_only", [])),
            "native_tool": xval.get("native_tool", ""),
        }

    cost = metadata.get("cost_impact")
    if isinstance(cost, dict) and cost.get("success"):
        ci["cost_impact"] = {
            "total_monthly_delta": cost.get("total_monthly_delta", 0.0),
            "total_annual_delta": cost.get("total_annual_delta", 0.0),
            "confidence": cost.get("confidence", "estimated"),
        }

    lz = metadata.get("landing_zone")
    if isinstance(lz, dict) and lz.get("detected"):
        ci["landing_zone"] = {
            "detected": True,
            "type": lz.get("type"),
            "inherited_policies_count": len(lz.get("inherited_policies", [])),
        }

    return ci


@dashboard_app.command("push")
def push(
    project_label: Annotated[
        str,
        typer.Option(
            "--project-label",
            help="Project label [a-z0-9-]{1,63}",
        ),
    ],
    client_label: Annotated[
        str | None,
        typer.Option("--client-label", help="Client label (Agency tier)"),
    ] = None,
    api_key: Annotated[
        str | None,
        typer.Option("--api-key", help="API key override"),
    ] = None,
    scan_id: Annotated[
        str | None,
        typer.Option("--scan-id", help="Specific cached scan hash"),
    ] = None,
) -> None:
    """Push cached assessment to the ComplyForm dashboard."""
    from complyform.core.auth.license import LicenseManager
    from complyform.core.auth.tier_enforcement import (
        check_feature,
        resolve_tier_info,
    )
    from complyform.core.cache import ScanCache

    # 1. Resolve tier and check feature
    mgr = LicenseManager()
    cache = mgr.load_cache()
    tier_info = resolve_tier_info(cache)

    try:
        check_feature("hosted_dashboard", tier_info)
    except FeatureNotAvailableError:
        raise FeatureNotAvailableError(
            "hosted_dashboard",
            tier_info.tier,
        ) from None

    # 2. Load cached assessment
    scan_cache = ScanCache()
    result = scan_cache.read(scan_id) if scan_id else scan_cache.latest()

    if result is None:
        raise NoCachedAssessmentError(scan_id or "")

    resources, metadata = result

    # 3. Resolve API key
    resolved_key = _resolve_api_key(api_key)

    # 4. Build push payload
    cloud = metadata.get("cloud", "unknown")
    state_hash = metadata.get("state_hash", "sha256:unknown")
    prefix = state_hash.split(":")[-1][:16] if ":" in state_hash else state_hash[:16]
    cache_dir = Path.home() / ".complyform" / "cache"
    entry_dir = cache_dir / prefix

    # Try to load assessment results
    assessment_path = entry_dir / "assessment.json"
    assessment: dict[str, Any] = {}
    if assessment_path.exists():
        assessment = json.loads(
            assessment_path.read_text(encoding="utf-8"),
        )

    frameworks = assessment.get("frameworks", [])
    score = assessment.get("score", 0.0)
    passed = assessment.get("passed", 0)
    failed = assessment.get("failed", 0)
    manual_review = assessment.get("manual_review", 0)
    not_assessed = assessment.get("not_assessed", 0)
    severity_counts = assessment.get("severity_counts", {})
    findings = assessment.get("findings", [])

    payload: dict[str, Any] = {
        "project_label": project_label,
        "client_label": client_label,
        "cloud": cloud,
        "frameworks": frameworks,
        "scan_source": "state",
        "score": score,
        "passed": passed,
        "failed": failed,
        "manual_review": manual_review,
        "not_assessed": not_assessed,
        "severity_counts": severity_counts,
        "resource_count": len(resources),
        "assessment_duration_ms": assessment.get("duration_ms", 0),
        "findings": findings,
        "state_hash": state_hash,
    }

    # Cloud intelligence extension
    ci_payload = _build_cloud_intelligence_payload(metadata)
    if ci_payload:
        payload["cloud_intelligence"] = ci_payload

    # 5. POST to API
    import httpx

    try:
        resp = httpx.post(
            f"{_API_BASE}/v1/dashboard/push",
            json=payload,
            headers={"X-API-Key": resolved_key},
            timeout=30,
        )
    except httpx.HTTPError as exc:
        raise ComplyFormError(
            title="Dashboard Push Failed",
            message=f"Network error: {exc}",
            fix="Check your network connection and try again.",
        ) from exc

    if resp.status_code == 401:
        raise ComplyFormError(
            title="Invalid API Key",
            message="The API key was rejected.",
            fix="complyform config set api_key <valid-key>",
            error_code=6,
        )

    if resp.status_code == 403:
        data = resp.json()
        raise ComplyFormError(
            title="Dashboard Push Blocked",
            message=data.get("error", "Access denied"),
            fix="Upgrade at https://complyform.dev/pricing",
        )

    if resp.status_code == 409:
        data = resp.json()
        raise ComplyFormError(
            title="Dashboard Push Conflict",
            message=data.get("error", "Conflict"),
            fix="Check your project limit or retry.",
        )

    if resp.status_code != 200:
        raise ComplyFormError(
            title="Dashboard Push Failed",
            message=f"API returned {resp.status_code}: {resp.text}",
            fix="Contact support if the issue persists.",
        )

    result_data = resp.json()
    delta = result_data.get("score_delta")
    if delta is not None:
        sign = "+" if delta > 0 else ""
        delta_str = f" ({sign}{delta:.1f})"
    else:
        delta_str = ""
    findings_count = len(findings)

    _stderr.print(
        f"[green]Pushed to dashboard:[/green] score {score:.1f}"
        f"{delta_str}, {findings_count} findings"
    )


@dashboard_app.command("project-configure")
def project_configure(
    project_label: Annotated[
        str,
        typer.Option(
            "--project-label",
            help="REQUIRED. Must already exist (push first).",
        ),
    ] = ...,  # type: ignore[assignment]
    state_source: Annotated[
        str | None,
        typer.Option(
            "--state-source",
            help="State file path for drift monitoring "
            "(gs://, s3://, app.terraform.io/...)",
        ),
    ] = None,
    frameworks: Annotated[
        str | None,
        typer.Option(
            "--frameworks",
            help="Comma-separated framework IDs to monitor",
        ),
    ] = None,
    drift_mode: Annotated[
        str | None,
        typer.Option(
            "--drift-mode",
            help="scheduled or event_driven",
        ),
    ] = None,
    drift_alerts: Annotated[
        str | None,
        typer.Option(
            "--drift-alerts",
            help="on or off",
        ),
    ] = None,
    alert_email: Annotated[
        str | None,
        typer.Option("--alert-email", help="Override email for drift alerts"),
    ] = None,
    alert_threshold: Annotated[
        int | None,
        typer.Option(
            "--alert-threshold",
            help="Score drop threshold (1-50, default: 5)",
        ),
    ] = None,
    alert_webhook: Annotated[
        str | None,
        typer.Option(
            "--alert-webhook",
            help="Webhook URL for drift alerts",
        ),
    ] = None,
    tfc_token: Annotated[
        str | None,
        typer.Option("--tfc-token", help="Terraform Cloud API token"),
    ] = None,
    api_key: Annotated[
        str | None,
        typer.Option("--api-key", help="API key override"),
    ] = None,
) -> None:
    """Configure drift monitoring for an existing dashboard project."""
    import httpx
    from rich.panel import Panel

    # 1. Resolve API key
    resolved_key = _resolve_api_key(api_key)

    # 2. Build request body
    body: dict[str, Any] = {}

    if drift_mode is not None:
        if drift_mode not in ("scheduled", "event_driven"):
            raise ComplyFormError(
                title="Invalid Drift Mode",
                message=f"Invalid drift_mode: {drift_mode}",
                fix="Use --drift-mode=scheduled or --drift-mode=event_driven",
            )
        body["drift_mode"] = drift_mode

    if drift_alerts is not None:
        if drift_alerts == "on":
            body["drift_alerts"] = True
        elif drift_alerts == "off":
            body["drift_alerts"] = False
        else:
            raise ComplyFormError(
                title="Invalid Drift Alerts Value",
                message=f"Invalid drift_alerts value: {drift_alerts}",
                fix="Use --drift-alerts=on or --drift-alerts=off",
            )

    if state_source is not None:
        body["state_source"] = state_source

    if frameworks is not None:
        body["frameworks"] = [f.strip() for f in frameworks.split(",")]

    if alert_email is not None:
        body["alert_email"] = alert_email

    if alert_threshold is not None:
        if not 1 <= alert_threshold <= 50:
            raise ComplyFormError(
                title="Invalid Alert Threshold",
                message=f"Threshold must be 1-50, got {alert_threshold}",
                fix="Use --alert-threshold with a value between 1 and 50",
            )
        body["alert_threshold"] = alert_threshold

    if alert_webhook is not None:
        body["alert_webhook"] = alert_webhook

    if tfc_token is not None:
        body["tfc_token"] = tfc_token

    # 3. POST to API (project_label is used as project_id)
    project_id = project_label

    try:
        resp = httpx.post(
            f"{_API_BASE}/v1/dashboard/projects/{project_id}/configure",
            json=body,
            headers={"X-API-Key": resolved_key},
            timeout=30,
        )
    except httpx.HTTPError as exc:
        raise ComplyFormError(
            title="Configure Failed",
            message=f"Network error: {exc}",
            fix="Check your network connection and try again.",
        ) from exc

    if resp.status_code == 401:
        raise ComplyFormError(
            title="Invalid API Key",
            message="The API key was rejected.",
            fix="complyform config set api_key <valid-key>",
            error_code=6,
        )

    if resp.status_code == 403:
        raise FeatureNotAvailableError(
            "drift_alerts",
            "your current",
        )

    if resp.status_code == 404:
        raise ComplyFormError(
            title="Project Not Found",
            message=f"Project '{project_label}' not found.",
            fix="Push a scan first: complyform dashboard push --project-label=...",
        )

    if resp.status_code != 200:
        raise ComplyFormError(
            title="Configure Failed",
            message=f"API returned {resp.status_code}: {resp.text}",
            fix="Contact support if the issue persists.",
        )

    result_data = resp.json()
    _stderr.print(f"[green]Drift monitoring configured for '{project_label}'[/green]")

    # Show event-driven setup instructions if present
    instructions = result_data.get("setup_instructions")
    webhook_secret = result_data.get("webhook_secret")

    if instructions and webhook_secret:
        _stderr.print(
            Panel(
                f"Secret: {webhook_secret}\nThis secret will not be shown again.",
                title="WEBHOOK SECRET — SAVE THIS NOW",
                style="yellow",
            )
        )
        _stderr.print(f"Cloud: {instructions['cloud']}")
        _stderr.print(f"Webhook URL: {instructions['webhook_url']}")
        _stderr.print(f"Terraform module: {instructions['terraform_module_url']}")
        _stderr.print(f"\n{instructions['quickstart']}")


# Replace the stub dashboard command in main app
app.registered_commands = [
    cmd for cmd in app.registered_commands if cmd.name != "dashboard"
]
app.add_typer(
    dashboard_app,
    name="dashboard",
    rich_help_panel="Management",
)
