from __future__ import annotations

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

from autotouch_cli.exceptions import AutotouchInputError

from autotouch_cli.templates import TemplateRuntime


@dataclass(frozen=True)
class WebhookCommandRuntime:
    resolve_token: Callable[[Optional[str], bool], Optional[str]]
    request_api: Callable[..., Any]
    print_json: Callable[[Any, bool], None]
    load_json_input: Callable[..., Any]
    emit_webhooks_recipe: Callable[[argparse.Namespace, TemplateRuntime], None]
    template_runtime_factory: Callable[[], TemplateRuntime]


def cmd_webhooks_recipe(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    runtime.emit_webhooks_recipe(args, runtime.template_runtime_factory())


def cmd_webhooks_get(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "GET",
        f"/api/tables/{args.table_id}/webhook",
        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_webhooks_rotate(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "POST",
        f"/api/tables/{args.table_id}/webhook",
        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_webhooks_ingest(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    payload = runtime.load_json_input(
        inline_json=args.records_json,
        file_path=args.records_file,
        context="records",
        default=None,
    )
    if payload is None:
        raise AutotouchInputError("provide --records-json or --records-file")

    webhook_token = (
        str(args.webhook_token or "").strip()
        or str(os.environ.get("AUTOTOUCH_WEBHOOK_TOKEN") or "").strip()
        or str(os.environ.get("SMARTTABLE_WEBHOOK_TOKEN") or "").strip()
    )
    if not webhook_token:
        raise AutotouchInputError("missing webhook token. Pass --webhook-token or set AUTOTOUCH_WEBHOOK_TOKEN.")

    data = runtime.request_api(
        "POST",
        f"/api/webhooks/tables/{args.table_id}/ingest",
        base_url=args.base_url,
        token=None,
        payload=payload,
        extra_headers={"x-autotouch-token": webhook_token},
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_webhooks_subscriptions_list(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    params: Dict[str, Any] = {"limit": int(args.limit or 100)}
    if args.include_disabled:
        params["includeDisabled"] = True
    data = runtime.request_api(
        "GET",
        "/api/webhook-subscriptions",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        params=params,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_webhooks_subscriptions_create(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload = runtime.load_json_input(
        inline_json=args.data_json,
        file_path=args.data_file,
        context="data",
        default=None,
    )
    if payload is None:
        payload = {
            "url": args.url,
            "events": args.events or [],
            "enabled": not bool(args.paused),
            "filters": runtime.load_json_input(
                inline_json=args.filters_json,
                file_path=args.filters_file,
                context="filters",
                default={},
            )
            or {},
            "metadata": runtime.load_json_input(
                inline_json=args.metadata_json,
                file_path=args.metadata_file,
                context="metadata",
                default={},
            )
            or {},
        }
        if args.retry_policy_json or args.retry_policy_file:
            payload["retryPolicy"] = runtime.load_json_input(
                inline_json=args.retry_policy_json,
                file_path=args.retry_policy_file,
                context="retry-policy",
                default={},
            ) or {}
    data = runtime.request_api(
        "POST",
        "/api/webhook-subscriptions",
        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_webhooks_subscriptions_get(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "GET",
        f"/api/webhook-subscriptions/{args.subscription_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 cmd_webhooks_subscriptions_update(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload = runtime.load_json_input(
        inline_json=args.data_json,
        file_path=args.data_file,
        context="data",
        default={},
    )
    data = runtime.request_api(
        "PATCH",
        f"/api/webhook-subscriptions/{args.subscription_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_webhooks_subscriptions_delete(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "DELETE",
        f"/api/webhook-subscriptions/{args.subscription_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 cmd_webhooks_subscriptions_pause(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "POST",
        f"/api/webhook-subscriptions/{args.subscription_id}/pause",
        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_webhooks_subscriptions_resume(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "POST",
        f"/api/webhook-subscriptions/{args.subscription_id}/resume",
        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_webhooks_subscriptions_rotate_secret(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    data = runtime.request_api(
        "POST",
        f"/api/webhook-subscriptions/{args.subscription_id}/rotate-secret",
        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_webhooks_subscriptions_test(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload = runtime.load_json_input(
        inline_json=args.data_json,
        file_path=args.data_file,
        context="data",
        default={},
    )
    request_payload: Dict[str, Any] = {"data": payload or {}}
    if getattr(args, "event_type", None):
        request_payload["eventType"] = str(args.event_type).strip()
    data = runtime.request_api(
        "POST",
        f"/api/webhook-subscriptions/{args.subscription_id}/test",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        payload=request_payload,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_webhooks_deliveries_list(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    params: Dict[str, Any] = {"limit": int(args.limit or 100)}
    if args.subscription_id:
        params["subscriptionId"] = args.subscription_id
    if args.status:
        params["status"] = args.status
    if args.event_type:
        params["eventType"] = args.event_type
    data = runtime.request_api(
        "GET",
        "/api/webhook-subscriptions/deliveries",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        params=params,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)


def cmd_webhooks_configure_ingest(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    payload: Dict[str, Any] = {}
    match_rule_id = str(getattr(args, "match_rule_id", None) or "").strip()
    match_column = str(getattr(args, "match_column", None) or "").strip()
    match_strategy = str(getattr(args, "match_strategy", None) or "").strip()
    duplicate_mode = str(getattr(args, "duplicate_mode", None) or "").strip()
    merge_mode = str(getattr(args, "merge_mode", None) or "").strip()
    if match_rule_id:
        payload["match_rule_id"] = match_rule_id
    if match_column:
        payload["match_column"] = match_column
    if match_strategy:
        payload["match_strategy"] = match_strategy
    if duplicate_mode:
        payload["duplicate_mode"] = duplicate_mode
    if merge_mode:
        payload["merge_mode"] = merge_mode
    if not payload:
        raise AutotouchInputError(
            "provide at least one of --match-rule-id, --match-column, --match-strategy, --duplicate-mode, or --merge-mode"
        )
    data = runtime.request_api(
        "PATCH",
        f"/api/tables/{args.table_id}/webhook/settings",
        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_webhooks_deliveries_attempts(args: argparse.Namespace, *, runtime: WebhookCommandRuntime) -> None:
    token = runtime.resolve_token(args.token, required=True)
    params: Dict[str, Any] = {"limit": int(args.limit or 100)}
    data = runtime.request_api(
        "GET",
        f"/api/webhook-subscriptions/deliveries/{args.delivery_id}/attempts",
        base_url=args.base_url,
        token=token,
        use_x_api_key=args.use_x_api_key,
        params=params,
        timeout=args.timeout,
        verbose=args.verbose,
    )
    runtime.print_json(data, args.compact)
