"""ContextGuard CLI.

Provides command-line access to scanning, auditing, and reporting.

Usage:
    contextguard scan <file>       Scan a text file for security risks
    contextguard audit             Audit dependencies in requirements.txt
    contextguard report            Generate a summary report from audit logs
"""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Optional

from contextguard import __version__
from contextguard.guard import Guard
from contextguard.dependency import DependencyAnalyzer


def _color(text: str, code: str) -> str:
    """ANSI color wrapper (no-op if not a TTY)."""
    if not sys.stdout.isatty():
        return text
    return f"\033[{code}m{text}\033[0m"


def _red(t: str) -> str:
    return _color(t, "91")


def _yellow(t: str) -> str:
    return _color(t, "93")


def _green(t: str) -> str:
    return _color(t, "92")


def _bold(t: str) -> str:
    return _color(t, "1")


def _risk_color(level: str) -> str:
    if level == "high":
        return _red(level.upper())
    if level == "medium":
        return _yellow(level.upper())
    return _green(level.upper())


# ------------------------------------------------------------------
# Commands
# ------------------------------------------------------------------


def cmd_scan(args: argparse.Namespace) -> int:
    """Scan a file or stdin for security risks."""
    guard = Guard(
        enable_logging=not args.no_log,
        log_backend=args.log_backend,
    )

    if args.file == "-":
        text = sys.stdin.read()
        source = "<stdin>"
    else:
        path = Path(args.file)
        if not path.exists():
            print(_red(f"Error: File not found: {args.file}"))
            return 1
        text = path.read_text(encoding="utf-8", errors="replace")
        source = str(path)

    result = guard.scan(text)

    if args.json:
        print(json.dumps(result.to_dict(), indent=2))
    else:
        print()
        print(_bold(f"ContextGuard Scan — {source}"))
        print("=" * 50)
        print(f"Risk Score : {result.risk_score:.4f}")
        print(f"Risk Level : {_risk_color(str(result.risk_level))}")
        print(f"Blocked    : {'Yes' if result.blocked else 'No'}")
        print(f"Entropy    : {result.entropy:.4f}")
        print()

        if result.injection.is_detected:
            print(_bold("Injection Detection:"))
            for m in result.injection.matches:
                print(f"  [{_red(m.label)}] \"{m.matched_text}\" (severity: {m.severity})")
            print()

        if result.secrets.is_detected:
            print(_bold("Secret Detection:"))
            for m in result.secrets.matches:
                print(f"  [{_yellow(m.label)}] {m.redacted} (entropy: {m.entropy})")
            print()

        if result.pii.is_detected:
            print(_bold("PII Detection:"))
            for m in result.pii.matches:
                print(f"  [{_yellow(m.label)}] {m.redacted}")
            print()

        if not result.detected_categories:
            print(_green("No security issues detected."))
        print()

    guard.close()
    return 0


def cmd_audit(args: argparse.Namespace) -> int:
    """Audit dependencies for security risks."""
    req_path = Path(args.requirements)
    if not req_path.exists():
        print(_red(f"Error: {args.requirements} not found"))
        return 1

    analyzer = DependencyAnalyzer(
        requirements_path=req_path,
        check_cves=not args.no_cve,
        check_pypi=not args.no_pypi,
        check_typosquatting=not args.no_typo,
    )

    print(_bold("ContextGuard Dependency Audit"))
    print("=" * 50)
    print(f"Scanning {req_path} ...")
    print()

    result = analyzer.audit()

    if args.json:
        data = {
            "total_packages": result.total_packages,
            "high_risk": result.high_risk,
            "medium_risk": result.medium_risk,
            "low_risk": result.low_risk,
            "overall_score": result.overall_score,
            "dependencies": [
                {
                    "name": d.name,
                    "version": d.version,
                    "risk_score": d.risk_score,
                    "issues": d.issues,
                    "cves": d.cves,
                    "last_release": d.last_release_date,
                    "is_stale": d.is_stale,
                    "typosquatting": d.typosquatting_warning,
                }
                for d in result.dependencies
            ],
        }
        print(json.dumps(data, indent=2))
    else:
        for dep in result.dependencies:
            status = "OK" if dep.risk_score < 0.3 else (
                "WARN" if dep.risk_score <= 0.7 else "HIGH"
            )
            color_fn = _green if status == "OK" else (_yellow if status == "WARN" else _red)
            print(f"  {color_fn(f'[{status}]')} {dep.name}", end="")
            if dep.version:
                print(f" ({dep.version})", end="")
            print(f"  score={dep.risk_score:.2f}")
            for issue in dep.issues:
                print(f"        └─ {issue}")

        print()
        print(f"Total: {result.total_packages} packages")
        print(
            f"  {_red(f'{result.high_risk} high')} | "
            f"{_yellow(f'{result.medium_risk} medium')} | "
            f"{_green(f'{result.low_risk} low')}"
        )
        print(f"  Overall risk: {result.overall_score:.4f}")
        print()

    return 0


def cmd_report(args: argparse.Namespace) -> int:
    """Generate a report from audit logs."""
    guard = Guard(
        enable_logging=True,
        log_backend=args.log_backend,
        log_path=args.log_path,
    )

    logs = guard.get_audit_logs()
    guard.close()

    if not logs:
        print(_yellow("No audit logs found."))
        return 0

    if args.json:
        print(json.dumps(logs, indent=2))
        return 0

    print()
    print(_bold("ContextGuard Audit Report"))
    print("=" * 50)
    print(f"Total events: {len(logs)}")

    blocked = sum(1 for entry in logs if entry.get("blocked"))
    sanitized = sum(1 for entry in logs if entry.get("sanitized"))
    high = sum(1 for entry in logs if entry.get("risk_level") == "high")
    medium = sum(1 for entry in logs if entry.get("risk_level") == "medium")

    print(f"Blocked    : {blocked}")
    print(f"Sanitized  : {sanitized}")
    print(f"High risk  : {high}")
    print(f"Medium risk: {medium}")
    print()

    # Show last 10 events
    print(_bold("Recent Events (last 10):"))
    print("-" * 50)
    for entry in logs[-10:]:
        ts = entry.get("timestamp", "?")[:19]
        score = entry.get("risk_score", 0)
        level = entry.get("risk_level", "?")
        cats = ", ".join(entry.get("detected_categories", [])[:3])
        preview = entry.get("prompt_preview", "")[:60]
        print(f"  {ts}  score={score:.2f}  {_risk_color(level)}  [{cats}]")
        if preview:
            print(f"    └─ {preview}...")
    print()

    return 0


# ------------------------------------------------------------------
# Entry point
# ------------------------------------------------------------------


def main(argv: Optional[list[str]] = None) -> int:
    """CLI entry point."""
    parser = argparse.ArgumentParser(
        prog="contextguard",
        description="ContextGuard — LLM Security Middleware CLI",
    )
    parser.add_argument(
        "--version", action="version", version=f"%(prog)s {__version__}"
    )

    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # -- scan --
    scan_parser = subparsers.add_parser("scan", help="Scan a file for security risks")
    scan_parser.add_argument("file", help="File to scan (use '-' for stdin)")
    scan_parser.add_argument("--json", action="store_true", help="Output as JSON")
    scan_parser.add_argument("--no-log", action="store_true", help="Disable audit logging")
    scan_parser.add_argument(
        "--log-backend", choices=["json", "sqlite"], default="json"
    )

    # -- audit --
    audit_parser = subparsers.add_parser("audit", help="Audit dependencies")
    audit_parser.add_argument(
        "-r", "--requirements", default="requirements.txt",
        help="Path to requirements.txt"
    )
    audit_parser.add_argument("--json", action="store_true", help="Output as JSON")
    audit_parser.add_argument("--no-cve", action="store_true", help="Skip CVE checks")
    audit_parser.add_argument("--no-pypi", action="store_true", help="Skip PyPI freshness")
    audit_parser.add_argument("--no-typo", action="store_true", help="Skip typosquatting check")

    # -- report --
    report_parser = subparsers.add_parser("report", help="Generate audit report")
    report_parser.add_argument("--json", action="store_true", help="Output as JSON")
    report_parser.add_argument(
        "--log-backend", choices=["json", "sqlite"], default="json"
    )
    report_parser.add_argument("--log-path", default=None, help="Path to log file")

    args = parser.parse_args(argv)

    if args.command is None:
        parser.print_help()
        return 0

    commands = {
        "scan": cmd_scan,
        "audit": cmd_audit,
        "report": cmd_report,
    }

    return commands[args.command](args)


if __name__ == "__main__":
    sys.exit(main())
