/**
 * Torbat Pay API client — real backend only (MVP 14.0–14.5).
 * Browser → /api/payment BFF; SSR → direct upstream :8012
 */
import { getValidAccessToken, refreshSession } from "@/lib/auth";
import type {
  CapabilitiesResponse,
  HealthResponse,
  MetricsResponse,
  PaymentRecord,
  PermissionsCatalogResponse,
} from "@/modules/payment/types";

const PAYMENT_BASE =
  typeof window !== "undefined"
    ? "/api/payment"
    : process.env.PAYMENT_SERVICE_URL ||
      process.env.NEXT_PUBLIC_PAYMENT_API_URL ||
      "http://localhost:8012";

export class PaymentApiError extends Error {
  constructor(
    public status: number,
    public code: string,
    message: string,
    public details?: unknown
  ) {
    super(message);
    this.name = "PaymentApiError";
  }
}

type RequestOptions = RequestInit & {
  tenantId: string;
  auth?: boolean;
  idempotencyKey?: string;
};

async function request<T>(path: string, options: RequestOptions): Promise<T> {
  const { tenantId, auth = true, idempotencyKey, headers: customHeaders, ...init } = options;
  const headers = new Headers(customHeaders);
  if (!headers.has("Content-Type") && init.body) headers.set("Content-Type", "application/json");
  headers.set("X-Tenant-ID", tenantId);
  if (idempotencyKey) headers.set("Idempotency-Key", idempotencyKey);
  if (auth) {
    const token = await getValidAccessToken();
    if (token) headers.set("Authorization", `Bearer ${token}`);
  }
  const url = path.startsWith("http")
    ? path
    : `${PAYMENT_BASE.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;

  let res: Response;
  try {
    res = await fetch(url, { ...init, headers, cache: "no-store" });
  } catch (err) {
    const detail = err instanceof Error ? err.message : "network_error";
    throw new Error(`اتصال به سرویس تربت‌پی برقرار نشد — ${detail}`);
  }

  if (res.status === 401 && auth) {
    const refreshed = await refreshSession({ force: true });
    if (refreshed) {
      headers.set("Authorization", `Bearer ${refreshed}`);
      res = await fetch(url, { ...init, headers, cache: "no-store" });
    }
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    const detail = body?.error ?? body?.detail ?? {};
    throw new PaymentApiError(
      res.status,
      detail?.code || (typeof detail === "string" ? detail : "unknown_error"),
      detail?.message || (typeof detail === "string" ? detail : res.statusText),
      detail
    );
  }
  if (res.status === 204) return undefined as T;
  return res.json() as Promise<T>;
}

function crud(basePath: string) {
  return {
    list: (tenantId: string) => request<PaymentRecord[]>(basePath, { tenantId }),
    get: (tenantId: string, id: string) => request<PaymentRecord>(`${basePath}/${id}`, { tenantId }),
    create: (tenantId: string, body: Record<string, unknown>) =>
      request<PaymentRecord>(basePath, { tenantId, method: "POST", body: JSON.stringify(body) }),
    update: (tenantId: string, id: string, body: Record<string, unknown>) =>
      request<PaymentRecord>(`${basePath}/${id}`, {
        tenantId,
        method: "PATCH",
        body: JSON.stringify(body),
      }),
  };
}

export const paymentApi = {
  health: (): Promise<HealthResponse> => fetch(`${PAYMENT_BASE}/health`).then((r) => r.json()),
  capabilities: (tenantId: string) =>
    request<CapabilitiesResponse>("/capabilities", { tenantId }),
  metrics: (tenantId?: string) =>
    tenantId
      ? request<MetricsResponse>("/metrics", { tenantId })
      : fetch(`${PAYMENT_BASE}/metrics`).then((r) => r.json()),
  openapi: async (): Promise<Record<string, unknown>> => {
    const r = await fetch(`${PAYMENT_BASE}/openapi.json`);
    if (!r.ok) throw new PaymentApiError(r.status, "openapi_error", "OpenAPI در دسترس نیست");
    return r.json();
  },
  permissions: {
    catalog: (tenantId: string) =>
      request<PermissionsCatalogResponse>("/api/v1/permissions/catalog", { tenantId }),
  },
  audit: {
    list: (tenantId: string) => request<PaymentRecord[]>("/api/v1/audit", { tenantId }),
  },
  workspaces: crud("/api/v1/payment-workspaces"),
  bundleDefinitions: crud("/api/v1/bundle-definitions"),
  tenantBundles: crud("/api/v1/tenant-bundles"),
  featureToggles: crud("/api/v1/feature-toggles"),
  providerAssignments: crud("/api/v1/provider-assignments"),
  pspRegistrations: crud("/api/v1/psp-provider-registrations"),
  creditRegistrations: crud("/api/v1/credit-provider-registrations"),
  configurations: crud("/api/v1/configurations"),
  settings: crud("/api/v1/settings"),
  pspConnections: {
    ...crud("/api/v1/psp-connections"),
    test: (tenantId: string, id: string) =>
      request<Record<string, unknown>>(`/api/v1/psp-connections/${id}/test`, {
        tenantId,
        method: "POST",
        body: "{}",
      }),
  },
  pspRouting: crud("/api/v1/psp-routing-policies"),
  merchants: {
    list: (tenantId: string) => request<PaymentRecord[]>("/api/v1/merchant-accounts", { tenantId }),
    get: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/merchant-accounts/${id}`, { tenantId }),
    create: (tenantId: string, body: Record<string, unknown>) =>
      request<PaymentRecord>("/api/v1/merchant-accounts", {
        tenantId,
        method: "POST",
        body: JSON.stringify(body),
      }),
    submit: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/merchant-accounts/${id}/submit`, { tenantId, method: "POST", body: "{}" }),
    activate: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/merchant-accounts/${id}/activate`, { tenantId, method: "POST", body: "{}" }),
    suspend: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/merchant-accounts/${id}/suspend`, { tenantId, method: "POST", body: "{}" }),
    close: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/merchant-accounts/${id}/close`, { tenantId, method: "POST", body: "{}" }),
  },
  settlementProfiles: crud("/api/v1/merchant-settlement-profiles"),
  requests: {
    list: (tenantId: string) => request<PaymentRecord[]>("/api/v1/payment-requests", { tenantId }),
    get: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/payment-requests/${id}`, { tenantId }),
    create: (tenantId: string, body: Record<string, unknown>, idempotencyKey: string) =>
      request<PaymentRecord>("/api/v1/payment-requests", {
        tenantId,
        method: "POST",
        body: JSON.stringify(body),
        idempotencyKey,
      }),
    cancel: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/payment-requests/${id}/cancel`, { tenantId, method: "POST", body: "{}" }),
    verify: (tenantId: string, id: string, body?: Record<string, unknown>) =>
      request<PaymentRecord>(`/api/v1/payment-requests/${id}/verify`, {
        tenantId,
        method: "POST",
        body: JSON.stringify(body ?? { status: "paid" }),
      }),
  },
  transactions: {
    list: (tenantId: string) => request<PaymentRecord[]>("/api/v1/payment-transactions", { tenantId }),
    get: (tenantId: string, id: string) =>
      request<PaymentRecord>(`/api/v1/payment-transactions/${id}`, { tenantId }),
    bySource: (tenantId: string, service?: string, refId?: string) => {
      const sp = new URLSearchParams();
      if (service) sp.set("service", service);
      if (refId) sp.set("ref_id", refId);
      const q = sp.toString();
      return request<PaymentRecord[]>(`/api/v1/payment-transactions/by-source${q ? `?${q}` : ""}`, {
        tenantId,
      });
    },
  },
  ledger: {
    list: (tenantId: string) => request<PaymentRecord[]>("/api/v1/payment-ledger-entries", { tenantId }),
  },
};

export const PAYMENT_API_CATALOG = [
  { method: "GET", path: "/health", phase: "14.0" },
  { method: "GET", path: "/capabilities", phase: "14.0" },
  { method: "GET", path: "/metrics", phase: "14.0" },
  { method: "GET|POST", path: "/api/v1/payment-workspaces", phase: "14.0" },
  { method: "GET|POST", path: "/api/v1/tenant-bundles", phase: "14.0" },
  { method: "GET|POST", path: "/api/v1/feature-toggles", phase: "14.0" },
  { method: "GET|POST", path: "/api/v1/psp-connections", phase: "14.1" },
  { method: "POST", path: "/api/v1/psp-connections/{id}/test", phase: "14.1" },
  { method: "GET|POST", path: "/api/v1/merchant-accounts", phase: "14.2" },
  { method: "POST", path: "/api/v1/payment-requests", phase: "14.3" },
  { method: "POST", path: "/api/v1/payment-requests/{id}/verify", phase: "14.4" },
  { method: "GET", path: "/api/v1/payment-transactions", phase: "14.5" },
  { method: "GET", path: "/api/v1/payment-ledger-entries", phase: "14.5" },
] as const;
