// @File: src/lib/apiHub.ts
// @Desc: Typed fetch helpers for the "API Hub" admin pages. These talk to
//        /api/v1/admin/api-hub/* and require an admin Bearer token (same
//        pattern as adminApi.ts). The hub surfaces every outbound API
//        integration the portal uses — WHMCS, SMS, WhatsApp, SMTP,
//        push providers, and payment gateways — with per-provider
//        health, credential presence, and a live test-connection button.
import { getToken } from "@/lib/auth";

export type ProviderCategory = "integration" | "notification" | "payment";
export type ProviderStatusValue =
  | "connected"
  | "configured"
  | "error"
  | "not_configured";

export interface ProviderCredentialHint {
  name: string;
  present: boolean;
  masked_value: string | null;
  required: boolean;
  source?: "db" | "env" | "none";
  editable?: boolean;
  secret?: boolean;
  label?: string | null;
  hint?: string | null;
}

export interface CredentialUpdate {
  name: string;
  value: string;
}

export interface ProviderStatus {
  id: string;
  name: string;
  category: ProviderCategory;
  description: string;
  docs_url: string | null;
  status: ProviderStatusValue;
  status_message: string;
  last_checked_at: number | null;
  latency_ms: number | null;
  credentials: ProviderCredentialHint[];
  sandbox_mode: boolean | null;
  enabled: boolean | null;
  logo_hint: string | null;
  test_supported: boolean;
}

export interface ApiHubAggregate {
  integrations: ProviderStatus[];
  notifications: ProviderStatus[];
  payments: ProviderStatus[];
  summary: {
    total: number;
    connected: number;
    configured: number;
    error: number;
    not_configured: number;
  };
  generated_at: number;
}

export interface ProviderTestResponse {
  provider: string;
  ok: boolean;
  message: string;
  latency_ms: number | null;
  tested_at: number;
  outbound_ip: string | null;
}

function authHeaders(extra?: Record<string, string>): HeadersInit {
  const token = getToken();
  return {
    "Content-Type": "application/json",
    ...(token ? { Authorization: `Bearer ${token}` } : {}),
    ...(extra ?? {}),
  };
}

async function handleJson<T>(res: Response): Promise<T> {
  const raw = await res.text();
  let data: unknown = null;
  if (raw) {
    try {
      data = JSON.parse(raw);
    } catch {
      data = raw;
    }
  }
  if (!res.ok) {
    const detail =
      (data && typeof data === "object" && "detail" in (data as Record<string, unknown>)
        ? String((data as Record<string, unknown>).detail)
        : null) || res.statusText || "Request failed";
    throw new Error(detail);
  }
  return data as T;
}

const BASE = "/api/v1/admin/api-hub";

export async function fetchApiHubStatus(): Promise<ApiHubAggregate> {
  const res = await fetch(`${BASE}/status`, { headers: authHeaders() });
  return handleJson<ApiHubAggregate>(res);
}

export async function fetchIntegrations(): Promise<ProviderStatus[]> {
  const res = await fetch(`${BASE}/integrations`, { headers: authHeaders() });
  return handleJson<ProviderStatus[]>(res);
}

export async function fetchNotifications(): Promise<ProviderStatus[]> {
  const res = await fetch(`${BASE}/notifications`, { headers: authHeaders() });
  return handleJson<ProviderStatus[]>(res);
}

export async function fetchPayments(): Promise<ProviderStatus[]> {
  const res = await fetch(`${BASE}/payments`, { headers: authHeaders() });
  return handleJson<ProviderStatus[]>(res);
}

export async function testProvider(
  providerId: string,
): Promise<ProviderTestResponse> {
  const res = await fetch(
    `${BASE}/providers/${encodeURIComponent(providerId)}/test`,
    { method: "POST", headers: authHeaders() },
  );
  return handleJson<ProviderTestResponse>(res);
}

export async function fetchProvider(
  providerId: string,
): Promise<ProviderStatus> {
  const res = await fetch(
    `${BASE}/providers/${encodeURIComponent(providerId)}`,
    { headers: authHeaders() },
  );
  return handleJson<ProviderStatus>(res);
}

export async function updateProviderCredentials(
  providerId: string,
  credentials: CredentialUpdate[],
): Promise<ProviderStatus> {
  const res = await fetch(
    `${BASE}/providers/${encodeURIComponent(providerId)}/credentials`,
    {
      method: "PUT",
      headers: authHeaders(),
      body: JSON.stringify({ credentials }),
    },
  );
  return handleJson<ProviderStatus>(res);
}

export async function deleteProviderCredential(
  providerId: string,
  name: string,
): Promise<ProviderStatus> {
  const res = await fetch(
    `${BASE}/providers/${encodeURIComponent(providerId)}/credentials/${encodeURIComponent(name)}`,
    { method: "DELETE", headers: authHeaders() },
  );
  return handleJson<ProviderStatus>(res);
}

// ---------- UI helpers ----------
export function statusTone(
  status: ProviderStatusValue,
): "green" | "yellow" | "red" | "slate" {
  switch (status) {
    case "connected":
      return "green";
    case "configured":
      return "yellow";
    case "error":
      return "red";
    default:
      return "slate";
  }
}

export function statusLabel(status: ProviderStatusValue): string {
  switch (status) {
    case "connected":
      return "Connected";
    case "configured":
      return "Configured";
    case "error":
      return "Error";
    default:
      return "Not configured";
  }
}

export function formatRelativeTimestamp(epochSeconds: number | null): string {
  if (!epochSeconds) return "Never tested";
  const diffSec = Math.max(0, Math.floor(Date.now() / 1000 - epochSeconds));
  if (diffSec < 60) return `${diffSec}s ago`;
  if (diffSec < 3600) return `${Math.floor(diffSec / 60)}m ago`;
  if (diffSec < 86400) return `${Math.floor(diffSec / 3600)}h ago`;
  return `${Math.floor(diffSec / 86400)}d ago`;
}