from __future__ import annotations

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

from autotouch_cli.exceptions import AutotouchInputError


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


def _normalize_secret_name(name: Any) -> str:
    normalized = str(name or "").strip().lower()
    if not normalized:
        raise AutotouchInputError("workspace secret name is required")
    return normalized


def _build_workspace_secret_payload(
    args: argparse.Namespace,
    *,
    runtime: WorkspaceSecretCommandRuntime,
) -> Dict[str, Any]:
    payload = runtime.load_json_input(
        inline_json=getattr(args, "data_json", None),
        file_path=getattr(args, "data_file", None),
        context="data",
        default=None,
    )
    if payload is not None:
        if not isinstance(payload, dict):
            raise AutotouchInputError("workspace-secrets set payload must be a JSON object")
    else:
        payload = {
            "name": _normalize_secret_name(getattr(args, "name", None)),
            "value": runtime.normalize_string_value(getattr(args, "value", None)),
        }

    name = _normalize_secret_name(payload.get("name"))
    value = runtime.normalize_string_value(payload.get("value"))
    if not value:
        raise AutotouchInputError("workspace secret value is required")
    return {
        "name": name,
        "value": value,
    }


def cmd_workspace_secrets_list(
    args: argparse.Namespace,
    *,
    runtime: WorkspaceSecretCommandRuntime,
) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "GET",
        "/api/workspace-secrets",
        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 cmd_workspace_secrets_set(
    args: argparse.Namespace,
    *,
    runtime: WorkspaceSecretCommandRuntime,
) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload = _build_workspace_secret_payload(args, runtime=runtime)
    data = runtime.request_api(
        "POST",
        "/api/workspace-secrets",
        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_workspace_secrets_delete(
    args: argparse.Namespace,
    *,
    runtime: WorkspaceSecretCommandRuntime,
) -> None:
    if not getattr(args, "yes", False):
        raise AutotouchInputError("workspace secret delete is destructive. Re-run with --yes to confirm.")

    token = runtime.resolve_token(args.token, required=True)
    secret_name = _normalize_secret_name(getattr(args, "name", None))
    data = runtime.request_api(
        "DELETE",
        f"/api/workspace-secrets/{secret_name}",
        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_workspace_secrets_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]],
    workspace_secret_schema_types: Sequence[str],
) -> None:
    pws = subparsers.add_parser(
        "workspace-secrets",
        help="Manage reusable org-scoped secrets for HTTP request columns",
        description=(
            "Manage reusable org-scoped secrets used by {{secrets.name}} templates in HTTP request columns "
            "and other templated features."
        ),
        epilog=(
            "Developer API keys need secrets:read / secrets:write scopes (or *) for these endpoints.\n"
            "Workspace secrets are optional; HTTP request columns can still use literal headers/body values."
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    pws._codex_examples = [
        "autotouch workspace-secrets set --name clearbit --value \"$CLEARBIT_API_KEY\"",
        "autotouch workspace-secrets list",
        "autotouch workspace-secrets delete --name clearbit --yes",
    ]
    ws_sub = pws.add_subparsers(dest="workspace_secret_cmd", required=True)

    pwsl = ws_sub.add_parser("list", help="List workspace secrets (masked values)")
    add_api_common_arguments(pwsl)
    pwsl.set_defaults(func=handlers["list"])

    pwss = ws_sub.add_parser(
        "set",
        help="Create or update a workspace secret",
        description="Create or update a workspace secret used by {{secrets.name}} template references.",
    )
    pwss.add_argument("--name", help="Secret/provider slug, for example clearbit")
    pwss.add_argument("--value", help="Secret value (for example an API key or bearer token)")
    pwss.add_argument("--data-json", help="Explicit workspace secret payload JSON")
    pwss.add_argument("--data-file", help="Path to workspace secret payload JSON file")
    add_api_common_arguments(pwss)
    pwss.set_defaults(func=handlers["set"])

    pwsd = ws_sub.add_parser("delete", help="Delete a workspace secret")
    pwsd.add_argument("--name", required=True, help="Secret/provider slug to delete")
    pwsd.add_argument("--yes", action="store_true", help="Confirm deletion")
    add_api_common_arguments(pwsd)
    pwsd.set_defaults(func=handlers["delete"])

    pwsschema = ws_sub.add_parser("schema", help="Print workspace-secrets payload schemas")
    pwsschema.add_argument("--type", choices=["all", *workspace_secret_schema_types], default="all")
    pwsschema.add_argument("--out-file", help="Write schema JSON to file")
    add_output_formatting_arguments(pwsschema)
    pwsschema.set_defaults(func=handlers["schema"])
