"""CLI commands for MLD experiment management.

Provides: mld experiment list, get, create, data, results, export, delete
"""

from __future__ import annotations

import argparse
import json
import sys


def register_experiment_parser(subparsers: argparse._SubParsersAction) -> None:
    """Register the 'experiment' subcommand group."""
    _F = argparse.RawDescriptionHelpFormatter

    exp_parser = subparsers.add_parser(
        "experiment",
        formatter_class=_F,
        help="Manage experiments",
        description="List, view, create, and export experiments.",
    )
    exp_sub = exp_parser.add_subparsers(dest="experiment_command")

    # -- experiment list --
    list_parser = exp_sub.add_parser("list", help="List experiments")
    list_parser.add_argument("--status", help="Filter by status")
    list_parser.add_argument("--type", dest="experiment_type", help="Filter by experiment type")
    list_parser.add_argument("--project-id", type=int, help="Filter by project ID")
    list_parser.add_argument("--search", help="Search by name")
    list_parser.add_argument("--limit", type=int, default=20, help="Max results (default: 20)")
    list_parser.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON")

    # -- experiment get --
    get_parser = exp_sub.add_parser("get", help="Get experiment details")
    get_parser.add_argument("id", type=int, help="Experiment ID")
    get_parser.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON")

    # -- experiment create --
    create_parser = exp_sub.add_parser("create", help="Create a new experiment")
    create_parser.add_argument("--name", required=True, help="Experiment name")
    create_parser.add_argument("--type", dest="experiment_type", default="custom", help="Experiment type")
    create_parser.add_argument("--project-id", type=int, help="Project ID")
    create_parser.add_argument("--notes", help="Notes")

    # -- experiment data --
    data_parser = exp_sub.add_parser("data", help="Get experiment design data")
    data_parser.add_argument("id", type=int, help="Experiment ID")
    data_parser.add_argument("--format", choices=["json", "csv"], default="json", help="Export format")

    # -- experiment results --
    results_parser = exp_sub.add_parser("results", help="Get analysis results")
    results_parser.add_argument("id", type=int, help="Experiment ID")
    results_parser.add_argument("--plugin", help="Filter by plugin ID")
    results_parser.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON")

    # -- experiment delete --
    delete_parser = exp_sub.add_parser("delete", help="Delete an experiment")
    delete_parser.add_argument("id", type=int, help="Experiment ID")
    delete_parser.add_argument("--yes", "-y", action="store_true", help="Skip confirmation")


def cmd_experiment(args: argparse.Namespace) -> None:
    """Dispatch experiment subcommands."""
    if args.experiment_command == "list":
        _cmd_list(args)
    elif args.experiment_command == "get":
        _cmd_get(args)
    elif args.experiment_command == "create":
        _cmd_create(args)
    elif args.experiment_command == "data":
        _cmd_data(args)
    elif args.experiment_command == "results":
        _cmd_results(args)
    elif args.experiment_command == "delete":
        _cmd_delete(args)
    else:
        print("Usage: mld experiment <list|get|create|data|results|delete>", file=sys.stderr)
        sys.exit(1)


def _get_client():
    """Create an MLDClient from stored config."""
    try:
        from mld_sdk.client import MLDClient

        return MLDClient()
    except ImportError:
        print(
            "Error: httpx is required. Install with: pip install mld-sdk[client]",
            file=sys.stderr,
        )
        sys.exit(1)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


def _print_json(data: object) -> None:
    print(json.dumps(data, indent=2, default=str))


def _print_experiment_table(experiments: list[dict]) -> None:
    """Print experiments as a formatted table."""
    if not experiments:
        print("No experiments found.")
        return

    # Header
    print(f"{'ID':<6} {'Name':<30} {'Type':<15} {'Status':<12} {'Created':<20}")
    print("-" * 85)
    for exp in experiments:
        created = str(exp.get("created_at", ""))[:19]
        print(
            f"{exp.get('id', ''):<6} "
            f"{str(exp.get('name', ''))[:28]:<30} "
            f"{str(exp.get('experiment_type', ''))[:13]:<15} "
            f"{str(exp.get('status', ''))[:10]:<12} "
            f"{created:<20}"
        )
    print(f"\n{len(experiments)} experiment(s)")


def _print_experiment_detail(exp: dict) -> None:
    """Print a single experiment with details."""
    print(f"Experiment #{exp.get('id')}")
    print(f"  Name:   {exp.get('name')}")
    print(f"  Code:   {exp.get('experiment_code', '—')}")
    print(f"  Type:   {exp.get('experiment_type')}")
    print(f"  Status: {exp.get('status')}")
    if exp.get("project"):
        print(f"  Project: {exp.get('project')}")
    if exp.get("notes"):
        print(f"  Notes:  {exp.get('notes')}")
    if exp.get("tags"):
        print(f"  Tags:   {exp.get('tags')}")
    print(f"  Created: {exp.get('created_at')}")
    print(f"  Updated: {exp.get('updated_at')}")


def _cmd_list(args: argparse.Namespace) -> None:
    client = _get_client()
    experiments = client.experiments.list(
        status=args.status,
        experiment_type=args.experiment_type,
        project_id=args.project_id,
        search=args.search,
        limit=args.limit,
    )
    if args.json_output:
        _print_json(experiments)
    else:
        _print_experiment_table(experiments)
    client.close()


def _cmd_get(args: argparse.Namespace) -> None:
    client = _get_client()
    exp = client.experiments.get(args.id)
    if args.json_output:
        _print_json(exp)
    else:
        _print_experiment_detail(exp)
    client.close()


def _cmd_create(args: argparse.Namespace) -> None:
    client = _get_client()
    exp = client.experiments.create(
        name=args.name,
        experiment_type=args.experiment_type,
        project_id=args.project_id,
        notes=args.notes,
    )
    print(f"Created experiment #{exp.get('id')}: {exp.get('name')}")
    client.close()


def _cmd_data(args: argparse.Namespace) -> None:
    client = _get_client()
    if args.format == "csv":
        data = client.experiments.export_data(args.id, format="csv")
    else:
        data = client.experiments.get_data(args.id)
    _print_json(data) if isinstance(data, dict) else print(data)
    client.close()


def _cmd_results(args: argparse.Namespace) -> None:
    client = _get_client()
    if args.plugin:
        result = client.experiments.get_result(args.id, args.plugin)
        _print_json(result)
    else:
        results = client.experiments.get_results(args.id)
        if args.json_output:
            _print_json(results)
        else:
            if not results:
                print("No analysis results.")
            else:
                for r in results:
                    print(f"  Plugin: {r.get('plugin_id', '?')}")
                    print(f"  Updated: {r.get('updated_at', '?')}")
                    print()
    client.close()


def _cmd_delete(args: argparse.Namespace) -> None:
    if not args.yes:
        confirm = input(f"Delete experiment #{args.id}? [y/N] ").strip().lower()
        if confirm != "y":
            print("Cancelled.")
            return

    client = _get_client()
    client.experiments.delete(args.id)
    print(f"Deleted experiment #{args.id}")
    client.close()
