from __future__ import annotations

import argparse
from dataclasses import dataclass
from typing import Any, Callable, Dict, Optional, Sequence

from autotouch_cli.exceptions import AutotouchAPIError, AutotouchInputError


@dataclass(frozen=True)
class PromptCommandRuntime:
    resolve_token: Callable[[Optional[str], bool], Optional[str]]
    request_api: Callable[..., Any]
    print_json: Callable[[Any, bool], None]
    load_json_input: Callable[..., Any]


def cmd_prompts_list(
    args: argparse.Namespace,
    *,
    runtime: PromptCommandRuntime,
) -> None:
    token = runtime.resolve_token(args.token, required=True)
    params: Dict[str, str] = {}
    mode = getattr(args, "mode", None)
    if mode:
        params["mode"] = mode
    data = runtime.request_api(
        "GET",
        "/api/enrichments/prompt-templates",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        timeout=args.timeout,
        verbose=args.verbose,
        params=params,
    )
    runtime.print_json(data, args.compact)


def cmd_prompts_get(
    args: argparse.Namespace,
    *,
    runtime: PromptCommandRuntime,
) -> None:
    template_id = str(getattr(args, "id", "") or "").strip()
    if not template_id:
        raise AutotouchInputError("--id is required")

    token = runtime.resolve_token(args.token, required=True)
    # List all and filter client-side (no dedicated GET-by-id endpoint)
    data = runtime.request_api(
        "GET",
        "/api/enrichments/prompt-templates",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    if isinstance(data, list):
        match = next((t for t in data if t.get("id") == template_id), None)
        if not match:
            raise AutotouchAPIError(f"prompt template not found: {template_id}")
        runtime.print_json(match, args.compact)
    else:
        runtime.print_json(data, args.compact)


def cmd_prompts_create(
    args: argparse.Namespace,
    *,
    runtime: PromptCommandRuntime,
) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload = runtime.load_json_input(
        inline_json=getattr(args, "data_json", None),
        file_path=getattr(args, "data_file", None),
        context="data",
        default=None,
    )
    if not payload or not isinstance(payload, dict):
        raise AutotouchInputError("prompts create requires a JSON payload via --data-json or --data-file")

    data = runtime.request_api(
        "POST",
        "/api/enrichments/prompt-templates",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        payload=payload,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_prompts_update(
    args: argparse.Namespace,
    *,
    runtime: PromptCommandRuntime,
) -> None:
    template_id = str(getattr(args, "id", "") or "").strip()
    if not template_id:
        raise AutotouchInputError("--id is required")

    token = runtime.resolve_token(args.token, required=True)
    payload = runtime.load_json_input(
        inline_json=getattr(args, "data_json", None),
        file_path=getattr(args, "data_file", None),
        context="data",
        default=None,
    )
    if not payload or not isinstance(payload, dict):
        raise AutotouchInputError("prompts update requires a JSON payload via --data-json or --data-file")

    data = runtime.request_api(
        "PATCH",
        f"/api/enrichments/prompt-templates/{template_id}",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        payload=payload,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_prompts_delete(
    args: argparse.Namespace,
    *,
    runtime: PromptCommandRuntime,
) -> None:
    if not getattr(args, "yes", False):
        raise AutotouchInputError("prompt template delete is destructive. Re-run with --yes to confirm.")

    template_id = str(getattr(args, "id", "") or "").strip()
    if not template_id:
        raise AutotouchInputError("--id is required")

    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "DELETE",
        f"/api/enrichments/prompt-templates/{template_id}",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def register_prompts_subcommands(
    subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
    *,
    add_api_common_arguments: Callable[[argparse.ArgumentParser], None],
    add_output_formatting_arguments: Callable[[argparse.ArgumentParser], None],
    handlers: Dict[str, Callable[[argparse.Namespace], None]],
    prompt_template_schema_types: Sequence[str],
) -> None:
    pp = subparsers.add_parser(
        "prompts",
        help="Manage saved prompt templates for LLM enrichment columns",
        description=(
            "List, create, update, and delete prompt templates used by LLM enrichment columns. "
            "Templates can be scoped to a single user (private) or shared with the team."
        ),
        epilog=(
            "Developer API keys need prompts:read / prompts:write scopes (or *) for these endpoints."
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    pp._codex_examples = [
        'autotouch prompts list',
        'autotouch prompts list --mode agent',
        'autotouch prompts get --id <TEMPLATE_ID>',
        'autotouch prompts create --data-file prompt.json',
        'autotouch prompts delete --id <TEMPLATE_ID> --yes',
    ]
    pp_sub = pp.add_subparsers(dest="prompts_cmd", required=True)

    # list
    ppl = pp_sub.add_parser("list", help="List prompt templates")
    ppl.add_argument("--mode", choices=["basic", "agent"], help="Filter by mode")
    add_api_common_arguments(ppl)
    ppl.set_defaults(func=handlers["list"])

    # get
    ppg = pp_sub.add_parser("get", help="Get a single prompt template by ID")
    ppg.add_argument("--id", required=True, help="Prompt template ID")
    add_api_common_arguments(ppg)
    ppg.set_defaults(func=handlers["get"])

    # create
    ppc = pp_sub.add_parser(
        "create",
        help="Create a new prompt template",
        description="Create a new prompt template. Requires a JSON payload with name, content, type, and mode.",
    )
    ppc.add_argument("--data-json", help="Inline JSON payload")
    ppc.add_argument("--data-file", help="Path to JSON payload file")
    add_api_common_arguments(ppc)
    ppc.set_defaults(func=handlers["create"])

    # update
    ppu = pp_sub.add_parser(
        "update",
        help="Update an existing prompt template",
        description="Partially update a prompt template. Only include the fields you want to change.",
    )
    ppu.add_argument("--id", required=True, help="Prompt template ID")
    ppu.add_argument("--data-json", help="Inline JSON payload")
    ppu.add_argument("--data-file", help="Path to JSON payload file")
    add_api_common_arguments(ppu)
    ppu.set_defaults(func=handlers["update"])

    # delete
    ppd = pp_sub.add_parser("delete", help="Delete a prompt template")
    ppd.add_argument("--id", required=True, help="Prompt template ID")
    ppd.add_argument("--yes", action="store_true", help="Confirm deletion")
    add_api_common_arguments(ppd)
    ppd.set_defaults(func=handlers["delete"])

    # schema
    pps = pp_sub.add_parser("schema", help="Print prompt template payload schemas")
    pps.add_argument("--type", choices=["all", *prompt_template_schema_types], default="all")
    pps.add_argument("--out-file", help="Write schema JSON to file")
    add_output_formatting_arguments(pps)
    pps.set_defaults(func=handlers["schema"])
