"""``penbot baseline`` and ``penbot regression`` CLI handlers."""

from __future__ import annotations

import asyncio
import json
import sys
from pathlib import Path
from typing import Any

from src.utils.logging import get_logger

logger = get_logger(__name__)


# ---------------------------------------------------------------------------
# penbot baseline
# ---------------------------------------------------------------------------


def run_baseline(args: Any) -> None:
    """Entry-point for ``penbot baseline``."""
    action = getattr(args, "baseline_action", "create") or "create"

    if action == "list":
        _list_baselines(args)
    elif action == "create":
        _create_baseline(args)


def _create_baseline(args: Any) -> None:
    from src.regression.baseline import BaselineManager

    session_path = _resolve_session(args)
    if not session_path:
        return

    with open(session_path) as f:
        session = json.load(f)

    manager = BaselineManager()
    name = getattr(args, "name", None)
    record = manager.create_from_session(session, name=name)

    print(f"\nBaseline created: {record.name}")
    print(f"  Target: {record.target_name}")
    print(f"  Attacks: {record.total_attacks}")
    print(f"  Successful: {record.successful_attacks}")
    print(f"  Vuln score: {record.vulnerability_score:.1f}")
    print(f"  Saved to: baselines/{record.name}.json\n")


def _list_baselines(args: Any) -> None:
    from src.regression.baseline import BaselineManager

    manager = BaselineManager()
    baselines = manager.list_baselines()

    if not baselines:
        print("\nNo baselines found. Create one with: penbot baseline create --latest\n")
        return

    machine = getattr(args, "machine", False)
    if machine:
        print(json.dumps(baselines, indent=2))
        return

    print(f"\n{'Name':<30} {'Target':<20} {'Score':<8} {'Attacks':<10} {'Created'}")
    print("-" * 90)
    for bl in baselines:
        print(
            f"{bl['name']:<30} {bl['target_name']:<20} "
            f"{bl['vulnerability_score']:<8.1f} "
            f"{bl['successful_attacks']}/{bl['total_attacks']:<7} "
            f"{bl['created_at'][:19]}"
        )
    print()


# ---------------------------------------------------------------------------
# penbot regression
# ---------------------------------------------------------------------------


def run_regression(args: Any) -> None:
    """Entry-point for ``penbot regression``."""
    asyncio.run(_run_regression_async(args))


async def _run_regression_async(args: Any) -> None:
    from src.regression.baseline import BaselineManager

    manager = BaselineManager()

    baseline_name = getattr(args, "baseline", None)
    if baseline_name:
        baseline = manager.load(baseline_name)
    else:
        baseline = manager.load_latest()

    if not baseline:
        print("\nNo baseline found. Create one first with: penbot baseline create --latest\n")
        sys.exit(1)

    config_path = Path(args.config)
    if not config_path.exists():
        print(f"\nConfig file not found: {config_path}\n")
        sys.exit(1)

    print(f"\n{'='*60}")
    print("  REGRESSION TEST")
    print(f"{'='*60}")
    print(f"  Baseline: {baseline.name}")
    print(f"  Baseline score: {baseline.vulnerability_score:.1f}")
    print(f"  Baseline attacks: {baseline.total_attacks}")
    print(f"  Config: {config_path}")
    print(f"{'='*60}\n")

    print("  Running red-team session against target...")

    try:
        session = await _run_session(config_path)
    except Exception as exc:
        print(f"\n  Session failed: {exc}\n")
        sys.exit(1)

    result = manager.compare(baseline, session)

    _print_regression_report(result)

    fail_on_regression = getattr(args, "fail_on_regression", False)
    if fail_on_regression and result.has_regressions:
        print("  CI/CD: Exiting with code 1 due to regressions.\n")
        sys.exit(1)


async def _run_session(config_path: Path) -> dict:
    """Run a PenBot test session and return the final state as a dict."""
    from src.workflow.graph import create_pentest_workflow
    from src.workflow.state import create_initial_state

    with open(config_path) as f:
        config = json.load(f)

    target_name = config.get("name", config.get("target_name", "target"))
    target_type = "api" if config.get("type") in ("rest", "api") else "web_ui"
    max_attacks = config.get("max_attacks", 10)
    attack_group = config.get("attack_group", "prompt_engineering")

    initial_state = create_initial_state(
        target_name=target_name,
        target_type=target_type,
        target_config=config,
        attack_group=attack_group,
        max_attempts=max_attacks,
    )

    app = create_pentest_workflow()
    thread_id = f"regression_{initial_state['test_session_id']}"
    run_config = {"configurable": {"thread_id": thread_id}}

    result = await app.ainvoke(initial_state, config=run_config)
    return dict(result)


def _print_regression_report(result: Any) -> None:
    delta_symbol = "+" if result.score_delta >= 0 else ""
    print(f"  Baseline score: {result.baseline_score:.1f}")
    print(f"  Current score:  {result.current_score:.1f} ({delta_symbol}{result.score_delta:.1f})")
    print()

    if result.regressions:
        print(f"  REGRESSIONS ({len(result.regressions)}):")
        for r in result.regressions:
            print(f"    [REGRESSION] {r.agent_name} ({r.attack_type})")
            print(f"      Was: {r.baseline_outcome} → Now: {r.current_outcome}")
            print(f"      Query: {r.query_preview}")
        print()

    if result.improvements:
        print(f"  IMPROVEMENTS ({len(result.improvements)}):")
        for imp in result.improvements:
            print(f"    [IMPROVED] {imp.agent_name} ({imp.attack_type})")
            print(f"      Was: {imp.baseline_outcome} → Now: {imp.current_outcome}")
        print()

    print(f"  Unchanged blocked:   {result.unchanged_blocked}")
    print(f"  Unchanged succeeded: {result.unchanged_succeeded}")
    print()

    if result.has_regressions:
        print("  VERDICT: REGRESSIONS DETECTED\n")
    else:
        print("  VERDICT: NO REGRESSIONS\n")


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _resolve_session(args: Any) -> Path | None:
    session_id = getattr(args, "session", None)
    use_latest = getattr(args, "latest", False)

    sessions_dir = Path("sessions")
    if not sessions_dir.exists():
        print("No sessions directory found.")
        return None

    if use_latest or not session_id:
        files = sorted(sessions_dir.glob("*.json"), key=lambda p: p.stat().st_mtime, reverse=True)
        if not files:
            print("No sessions found.")
            return None
        return files[0]

    direct = sessions_dir / f"{session_id}.json"
    if direct.exists():
        return direct

    for p in sessions_dir.glob("*.json"):
        if session_id in p.stem:
            return p

    print(f"Session '{session_id}' not found.")
    return None
