"""
Belief Revision System - Command Line Interface

Provides CLI commands for:
- Listing/inspecting worlds and proposals
- Running smoke tests
- Discovering cross-domain analogs
- Evaluating proposals
"""
from __future__ import annotations

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

from .storage import CASStore
from .discovery import DomainSpec, suggest_analogs, persist_analog_proposals, domain_stats
from .evaluator import (
    evaluate_with_registry, run_smoke_tests, available_tests,
    EvaluationConfig
)
from .domains import registry


def cmd_worlds(store: CASStore, args: argparse.Namespace) -> None:
    """List all worlds."""
    worlds = store.list_worlds(domain_id=args.domain)
    if not worlds:
        print("No worlds found.")
        return

    for w in worlds:
        print(f"  {w['domain_id']}:{w['version_label']} -> {w['hash'][:12]}... ({w['created_utc']})")


def cmd_stats(store: CASStore, args: argparse.Namespace) -> None:
    """Show domain statistics."""
    stats = domain_stats(store, args.domain, args.world or "green")
    if "error" in stats:
        print(f"Error: {stats['error']}")
        return

    print(f"Domain: {stats['domain_id']}:{stats['world_label']}")
    print(f"  Nodes: {stats['num_nodes']}")
    print(f"  Edges: {stats['num_edges']}")
    print(f"  Patterns: {stats['num_patterns']}")
    print(f"  Evidence: {stats['num_evidence']}")
    print(f"  Created: {stats['created_utc']}")


def cmd_proposals(store: CASStore, args: argparse.Namespace) -> None:
    """List proposals."""
    proposals = store.list_proposals(status=args.status, limit=args.limit)
    if not proposals:
        print("No proposals found.")
        return

    for p in proposals:
        score_str = f"{p['score']:.3f}" if p['score'] is not None else "N/A"
        print(f"  [{p['status']}] {p['proposal_id'][:16]}... ({p['kind']}) score={score_str}")


def cmd_smoke(store: CASStore, args: argparse.Namespace) -> None:
    """Run smoke tests."""
    tests, fails, msgs = run_smoke_tests(
        store,
        domain_id=args.domain,
        world_label=args.world or "green",
        level=args.level
    )

    print(f"Smoke tests for {args.domain}:{args.world or 'green'} (level={args.level})")
    print(f"  Ran: {tests}, Failed: {fails}")
    if args.verbose:
        for msg in msgs:
            print(f"    {msg}")


def cmd_discover(store: CASStore, args: argparse.Namespace) -> None:
    """Discover cross-domain analogs."""
    domains = [DomainSpec(d.split(":")[0], d.split(":")[-1] if ":" in d else "green")
               for d in args.domains]

    if args.persist:
        ids = persist_analog_proposals(
            store, domains,
            top_k=args.limit,
            min_score=args.min_score
        )
        print(f"Created {len(ids)} proposals")
        for pid in ids[:10]:
            print(f"  {pid}")
    else:
        suggestions = suggest_analogs(
            store, domains,
            top_k=args.limit,
            min_score=args.min_score
        )
        print(f"Found {len(suggestions)} potential analogs:")
        for s in suggestions:
            print(f"  [{s['score']:.3f}] {s['left']} <-> {s['right']}")
            if args.verbose:
                print(f"    Shared ops: {s['shared_operators']}")
                print(f"    Shared tokens: {s['shared_tokens'][:5]}...")


def cmd_evaluate(store: CASStore, args: argparse.Namespace) -> None:
    """Evaluate a proposal."""
    config = EvaluationConfig(
        base_world=args.base_world,
        acceptance_threshold=args.threshold
    )

    result = evaluate_with_registry(
        store,
        proposal_id=args.proposal_id,
        target_domain=args.domain,
        config=config
    )

    print(f"Evaluation result for {args.proposal_id[:16]}...")
    print(f"  Outcome: {result.outcome}")
    print(f"  Maturity delta: {result.delta:.4f}")
    print(f"  Tests run: {result.tests_run}, Failures: {result.failures}")
    if args.verbose:
        print(f"  Notes:\n{result.notes}")


def cmd_domains(store: CASStore, args: argparse.Namespace) -> None:
    """List registered domains and test levels."""
    tests = available_tests()
    if not tests:
        print("No domains registered.")
        return

    print("Registered domains:")
    for domain, levels in tests.items():
        print(f"  {domain}: {', '.join(levels)}")


def main(argv: Optional[List[str]] = None) -> int:
    """Main CLI entry point."""
    parser = argparse.ArgumentParser(
        prog="brs",
        description="Belief Revision System CLI"
    )
    parser.add_argument(
        "--db", "-d",
        type=Path,
        default=Path("./brs_data"),
        help="BRS database directory"
    )

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

    # worlds
    p_worlds = subparsers.add_parser("worlds", help="List worlds")
    p_worlds.add_argument("--domain", help="Filter by domain")

    # stats
    p_stats = subparsers.add_parser("stats", help="Show domain statistics")
    p_stats.add_argument("domain", help="Domain ID")
    p_stats.add_argument("--world", "-w", help="World version (default: green)")

    # proposals
    p_props = subparsers.add_parser("proposals", help="List proposals")
    p_props.add_argument("--status", "-s", help="Filter by status")
    p_props.add_argument("--limit", "-n", type=int, default=20, help="Max results")

    # smoke
    p_smoke = subparsers.add_parser("smoke", help="Run smoke tests")
    p_smoke.add_argument("domain", help="Domain ID")
    p_smoke.add_argument("--world", "-w", help="World version (default: green)")
    p_smoke.add_argument("--level", "-l", default="smoke", help="Test level")
    p_smoke.add_argument("--verbose", "-v", action="store_true", help="Show details")

    # discover
    p_disc = subparsers.add_parser("discover", help="Discover cross-domain analogs")
    p_disc.add_argument("domains", nargs="+", help="Domains (format: domain or domain:world)")
    p_disc.add_argument("--persist", "-p", action="store_true", help="Save as proposals")
    p_disc.add_argument("--limit", "-n", type=int, default=10, help="Max results")
    p_disc.add_argument("--min-score", type=float, default=0.35, help="Min similarity")
    p_disc.add_argument("--verbose", "-v", action="store_true", help="Show details")

    # evaluate
    p_eval = subparsers.add_parser("evaluate", help="Evaluate a proposal")
    p_eval.add_argument("proposal_id", help="Proposal ID")
    p_eval.add_argument("domain", help="Target domain")
    p_eval.add_argument("--base-world", default="green", help="Base world version")
    p_eval.add_argument("--threshold", type=float, default=0.0, help="Acceptance threshold")
    p_eval.add_argument("--verbose", "-v", action="store_true", help="Show details")

    # domains
    p_doms = subparsers.add_parser("domains", help="List registered domains")

    args = parser.parse_args(argv)

    if not args.command:
        parser.print_help()
        return 1

    # Initialize store
    store = CASStore(args.db)

    try:
        if args.command == "worlds":
            cmd_worlds(store, args)
        elif args.command == "stats":
            cmd_stats(store, args)
        elif args.command == "proposals":
            cmd_proposals(store, args)
        elif args.command == "smoke":
            cmd_smoke(store, args)
        elif args.command == "discover":
            cmd_discover(store, args)
        elif args.command == "evaluate":
            cmd_evaluate(store, args)
        elif args.command == "domains":
            cmd_domains(store, args)
        else:
            parser.print_help()
            return 1
    finally:
        store.close()

    return 0


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