/**
 * CursorHostFailureClassifier — Cursor SDK errors → HostFailure (WP-04).
 * Wraps existing sdk-failure-classifier; does not change production SessionManager path.
 */

import {
  buildSdkFailurePayloadFields,
  classifySdkFailureCategory,
  extractSdkErrorDetails,
  type SdkFailureCategory,
} from "../../../session/sdk-failure-classifier.ts";
import type { HostFailure, HostFailureKind } from "../../contracts/HostFailure.ts";

/** Map Cursor SDK failure categories onto HostFailureKind. */
export function mapCursorFailureCategoryToHostKind(
  category: SdkFailureCategory,
): HostFailureKind {
  switch (category) {
    case "transient_network":
      return "transient";
    case "rate_limited":
      return "rate_limited";
    case "cursor_sdk_first_turn_abort":
      return "session_lost";
    case "policy_blocked":
    case "policy_denied":
    case "approval_required":
      return "permission";
    case "precondition_changed":
    case "already_absent":
      return "invalid_request";
    case "tool_runtime_error":
      return "provider_unavailable";
    case "cursor_sdk_error_no_detail":
      return "delivery_unknown";
    case "unknown_sdk_error":
    default:
      return "unknown";
  }
}

export function isCursorHostFailureRetryable(kind: HostFailureKind): boolean {
  return (
    kind === "transient" ||
    kind === "rate_limited" ||
    kind === "session_busy" ||
    kind === "delivery_unknown"
  );
}

/**
 * Classify an unknown error into HostFailure using Cursor SDK heuristics.
 */
function asOptionalString(value: unknown): string | undefined {
  return typeof value === "string" && value.trim() ? value : undefined;
}

export function classifyCursorHostFailure(error: unknown): HostFailure {
  const extracted = extractSdkErrorDetails(error);
  const fields = buildSdkFailurePayloadFields({ raw: error });
  const fieldMessage = asOptionalString(fields.sdk_error_message);
  const fieldCode = asOptionalString(fields.sdk_error_code);
  const category = classifySdkFailureCategory({
    raw: error,
    error_message: extracted.sdk_error_message ?? fieldMessage,
  });
  const kind = mapCursorFailureCategoryToHostKind(category);
  const message =
    fieldMessage ||
    extracted.sdk_error_message ||
    (error instanceof Error ? error.message : String(error));
  return {
    kind,
    message,
    retryable: isCursorHostFailureRetryable(kind),
    rawCode: fieldCode ?? extracted.sdk_error_code,
    raw: {
      failure_category: category,
      ...fields,
      vendor: "cursor",
    },
  };
}
