"""CLI entrypoint for the cyberflage package."""

from __future__ import annotations

import argparse
import json
import sys
import time
import traceback
from typing import Any

from .app import CyberFlage
from .config import build_config, load_config_file
from .core.signals import Event, events_to_signals


def _format_signal_label(signal: str) -> str:
    label_map = {
        "suspicious_port_scan": "Suspicious port scan detected",
        "credential_dump_attempt": "Credential dump attempt observed",
        "failed_auth_burst": "Rapid authentication failures",
        "new_external_ip": "Unknown external IP detected",
        "high_cpu": "Rapid activity spike (high CPU)",
    }
    return label_map.get(signal, signal.replace("_", " ").capitalize())


def _one_line_explanation(state: dict[str, Any]) -> str:
    level = str(state.get("level", "LOW"))
    signals = state.get("signals", [])
    if not isinstance(signals, list):
        signals = []
    if level == "CRITICAL":
        return "Critical risk detected due to multiple strong suspicious indicators."
    if level == "HIGH":
        return "High risk detected due to abnormal activity patterns and stacked signals."
    if level == "MEDIUM":
        return "Moderate risk detected; suspicious behavior should be investigated."
    return "Low risk state detected; monitoring remains stable."


def _print_summary(state: dict[str, Any], *, header: str = "CyberFlage Summary") -> None:
    reasons = state.get("explanation", [])
    if not isinstance(reasons, list):
        reasons = []
    signals = state.get("signals", [])
    if not isinstance(signals, list):
        signals = []
    action = state.get("action", "No action.")
    level = state.get("level", "LOW")
    risk_score = state.get("risk_score", 0)
    scenario = state.get("scenario")
    print("====================================")
    print(header)
    if scenario:
        print(f"Scenario: {scenario}")
    print("====================================")
    print("")
    print("Signals:")
    if signals:
        for signal in signals:
            print(f"- {_format_signal_label(str(signal))}")
    else:
        print("- No suspicious signals detected")
    print("")
    print(f"Risk Score: {risk_score} ({level})")
    print("")
    print("Action:")
    print(f"- {action}")
    print("")
    print("Explanation:")
    if reasons:
        for reason in reasons:
            print(f"- {reason}")
    else:
        print("- No significant risk contributors detected")
    print("")
    print(_one_line_explanation(state))
    print("CyberFlage detected suspicious behavior and responded safely.")
    print("====================================")


def _print_start_guide() -> None:
    print("====================================")
    print("Welcome to CyberFlage")
    print("")
    print("CyberFlage observes system behavior, explains risk changes, and recommends safe responses.")
    print("It uses an explicit pipeline: Event -> Signal -> Feature -> Risk -> Action.")
    print("")
    print("Quick demo commands:")
    print("- cyberflage start --demo")
    print("- cyberflage start --present")
    print("- cyberflage start --run-once")
    print("- cyberflage start --config-file config.json --run-once")
    print("- cyberflage start --show-config")
    print("====================================")


def _scenario_narrative(title: str) -> str:
    narrative_map = {
        "Ransomware Simulation": "Simulating ransomware-like behavior: rapid file deletion pattern detected.",
        "Credential Attack Simulation": "Simulating account abuse: repeated authentication failures and unknown access source.",
    }
    return narrative_map.get(title, "Simulating suspicious behavior for explainable pipeline demonstration.")


def _run_demo(app: CyberFlage, *, present: bool = False) -> None:
    scenarios: list[tuple[str, list[Event]]] = [
        (
            "Ransomware Simulation",
            [
                Event(source="demo", event_type="suspicious_port_scan", severity=1.0),
                Event(source="demo", event_type="credential_dump_attempt", severity=1.0),
            ],
        ),
        (
            "Credential Attack Simulation",
            [
                Event(source="demo", event_type="failed_auth_burst", severity=0.8),
                Event(source="demo", event_type="new_external_ip", severity=0.7),
            ],
        ),
    ]

    pause_seconds = 1.2 if present else 0.0
    for title, events in scenarios:
        print("====================================")
        print(f"Scenario: {title}")
        print("====================================")
        print(_scenario_narrative(title))
        print("Pipeline: Event -> Signal -> Feature -> Risk -> Action")
        print("")
        print("Step 1/5 Event:")
        for event in events:
            print(f"- {event.event_type} (severity={event.severity})")
        if pause_seconds:
            time.sleep(pause_seconds)
        signals = events_to_signals(events)
        print("Step 2/5 Signal:")
        for signal in signals:
            print(f"- {signal.name} (+{signal.weight:.2f})")
        if pause_seconds:
            time.sleep(pause_seconds)
        level, features, risk_score, explanation = app.decision_engine.ingest_signals(signals)
        print("Step 3/5 Feature:")
        for feature in features:
            print(f"- {feature.name}: {feature.value:.2f}")
        if pause_seconds:
            time.sleep(pause_seconds)
        print(f"Step 4/5 Risk: {risk_score:.2f} ({level})")
        if pause_seconds:
            time.sleep(pause_seconds)
        action = app.deception_engine.evaluate(level)
        print(f"Step 5/5 Action: {action}")
        if pause_seconds:
            time.sleep(pause_seconds)
        state = {
            "scenario": title,
            "signals": [signal.name for signal in signals],
            "explanation": explanation,
            "risk_score": round(risk_score, 2),
            "level": level,
            "action": action,
        }
        _print_summary(state, header="Demo Result")


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    """Parse command-line arguments."""
    raw_argv = list(sys.argv[1:] if argv is None else argv)
    normalized_argv = raw_argv
    if raw_argv and raw_argv[0].startswith("-"):
        # Backward compatibility: allow legacy usage like `cyberflage --run-once`.
        normalized_argv = ["start", *raw_argv]

    parser = argparse.ArgumentParser(description="CyberFlage command interface.")
    subparsers = parser.add_subparsers(dest="command")
    start_parser = subparsers.add_parser(
        "start",
        help="Start CyberFlage pipeline execution.",
        description="Run CyberFlage with explicit pipeline: Event -> Signal -> Feature -> Risk -> Action.",
    )
    target = start_parser
    target.add_argument(
        "--config",
        type=str,
        default=None,
        help="JSON object string with configuration overrides.",
    )
    target.add_argument(
        "--config-file",
        type=str,
        default="config.json",
        help="Path to JSON config file (used if present).",
    )
    target.add_argument(
        "--run-once",
        action="store_true",
        help="Run one detection cycle and print a formatted summary.",
    )
    target.add_argument(
        "--demo",
        action="store_true",
        help="Run built-in demo scenarios with step-by-step pipeline output.",
    )
    target.add_argument(
        "--present",
        action="store_true",
        help="Presentation mode: demo with staged pauses and live-storytelling output.",
    )
    target.add_argument(
        "--show-config",
        action="store_true",
        help="Print effective config and exit.",
    )
    target.add_argument(
        "--debug",
        action="store_true",
        help="Enable debug mode with verbose errors.",
    )
    parsed = parser.parse_args(normalized_argv)
    setattr(parsed, "_raw_argv", raw_argv)
    return parsed


def main() -> int:
    """Run CyberFlage from CLI."""
    args = parse_args()
    if getattr(args, "command", None) is None:
        print("CyberFlage monitors activity, explains risk, and recommends safe responses.")
        print("Use 'cyberflage start --demo' to run demo.")
        print("Use 'cyberflage start --run-once' for a single cycle.")
        return 0

    overrides: dict[str, Any] | None = None

    try:
        file_overrides: dict[str, Any] = {}
        if getattr(args, "config_file", None):
            try:
                file_overrides = load_config_file(args.config_file)
            except ValueError as exc:
                if "not found" not in str(exc):
                    raise

        cli_overrides: dict[str, Any] = {}
        raw_config = getattr(args, "config", None)
        if raw_config:
            try:
                parsed = json.loads(raw_config)
            except json.JSONDecodeError as exc:
                raise ValueError(f"Invalid JSON for --config: {exc}") from exc
            if not isinstance(parsed, dict):
                raise ValueError("--config must be a JSON object.")
            cli_overrides = parsed

        if file_overrides or cli_overrides:
            overrides = {**file_overrides, **cli_overrides}

        config = build_config(overrides)
        if not getattr(args, "debug", False):
            config.setdefault("logging", {})
            config["logging"]["level"] = "ERROR"
        if args.show_config:
            print(json.dumps(config, indent=2))
            return 0

        if config.get("safety", {}).get("destructive_actions_enabled", False):
            print("WARNING: destructive actions are enabled.")
        else:
            print("Safety mode: destructive actions are disabled by default.")

        app = CyberFlage(config)
        if getattr(args, "present", False):
            _run_demo(app, present=True)
        elif getattr(args, "demo", False):
            _run_demo(app, present=False)
        elif getattr(args, "run_once", False):
            state = app.run_once()
            _print_summary(state, header="System Status")
        else:
            state = app.run_once()
            _print_summary(state, header="System Status")
            app.start_dashboard()
        return 0
    except ValueError as exc:
        print(f"Configuration error: {exc}")
        return 2
    except Exception as exc:
        print(f"Runtime error: {exc}. Re-run with --debug for traceback.")
        if getattr(args, "debug", False):
            traceback.print_exc()
        return 1


if __name__ == "__main__":
    raise SystemExit(main())
