// @File: src/lib/uptimerobotApi.ts
// @Desc: Typed fetch wrappers for the UptimeRobot Reseller Manager admin
//        and client endpoints. Mirrors the conventions in adminApi.ts —
//        authenticated via the app JWT from localStorage, JSON error
//        envelopes parsed into a single string message.
import { getToken } from "@/lib/auth";

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

async function handle<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;
}

// ---------- types ----------
export interface UptimePackage {
  id: number;
  slug: string;
  name: string;
  description: string | null;
  max_monitors: number;
  monitors_unlimited: boolean;
  max_alert_contacts: number;
  alert_contacts_unlimited: boolean;
  max_maintenance_windows: number;
  maintenance_windows_unlimited: boolean;
  max_status_pages: number;
  status_pages_unlimited: boolean;
  min_check_interval: number;
  allowed_monitor_types: string;
  public_status_page_allowed: boolean;
  api_monitoring_allowed: boolean;
  advanced_notifications_allowed: boolean;
  whmcs_product_id: number | null;
  terminate_action: "archive" | "delete";
  is_active: boolean;
  price_per_month: string | null;
  created_at: string;
  updated_at: string;
}

export type UptimePackageInput = Omit<
  UptimePackage,
  "id" | "created_at" | "updated_at"
>;

export interface UptimeSubscription {
  id: number;
  user_id: string;
  user_email: string | null;
  package_id: number;
  package_name: string | null;
  whmcs_service_id: number | null;
  whmcs_product_id: number | null;
  status: "active" | "suspended" | "terminated" | "none" | string;
  monitors_used: number;
  alert_contacts_used: number;
  maintenance_windows_used: number;
  status_pages_used: number;
  notes: string | null;
  activated_at: string | null;
  suspended_at: string | null;
  terminated_at: string | null;
  created_at: string;
  updated_at: string;
}

export interface UptimeMonitor {
  id: number;
  subscription_id: number;
  user_id: string;
  ur_monitor_id: string;
  friendly_name: string;
  monitor_type: string;
  url: string | null;
  keyword: string | null;
  port: number | null;
  interval_seconds: number;
  status: string;
  uptime_ratio_24h: string | null;
  uptime_ratio_7d: string | null;
  uptime_ratio_30d: string | null;
  response_time_ms: number | null;
  last_error: string | null;
  last_synced_at: string | null;
  paused: boolean;
  archived: boolean;
  created_at: string;
  updated_at: string;
}

export interface UptimeAlertContact {
  id: number;
  subscription_id: number;
  user_id: string;
  ur_contact_id: string;
  contact_type: string;
  friendly_name: string | null;
  value: string;
  verified: boolean;
  created_at: string;
  updated_at: string;
}

export interface UptimeMaintenanceWindow {
  id: number;
  subscription_id: number;
  user_id: string;
  ur_window_id: string;
  friendly_name: string;
  window_type: string;
  start_time: string | null;
  duration_minutes: number;
  status: string;
  created_at: string;
  updated_at: string;
}

export interface UptimeStatusPage {
  id: number;
  subscription_id: number;
  user_id: string;
  ur_page_id: string;
  friendly_name: string;
  standard_url: string | null;
  custom_url: string | null;
  monitor_ids: string[];
  created_at: string;
  updated_at: string;
}

export interface UptimeMeter {
  used: number;
  total: number | null;
  percent: number | null;
  unlimited: boolean;
}

export type UptimeWarningState =
  | "ok"
  | "warn_70"
  | "warn_85"
  | "critical_95"
  | "upgrade_required";

export interface UptimeTeamUsage {
  monitors: UptimeMeter;
  alert_contacts: UptimeMeter;
  status_pages: UptimeMeter;
  maintenance_windows: UptimeMeter;
  plan_name: string | null;
  warning_state: UptimeWarningState;
  warning_label: string;
  snapshot_at: string | null;
}

export interface UptimeApiSettings {
  api_key_present: boolean;
  api_key_masked: string | null;
  api_key_source: "db" | "env" | "none";
  last_sync_at: string | null;
  last_error_at: string | null;
  last_error_class: string | null;
  last_error_message: string | null;
}

export interface UptimeApiTestResult {
  ok: boolean;
  http_status: number | null;
  error_class: string | null;
  error_message: string | null;
  plan_name: string | null;
}

export interface UptimeSyncResult {
  ok: boolean;
  monitors_synced: number;
  contacts_synced: number;
  windows_synced: number;
  pages_synced: number;
  snapshot_id: number | null;
  error: string | null;
}

export interface UptimeApiLogItem {
  id: number;
  endpoint: string;
  method: string;
  status: string;
  error_class: string | null;
  http_status: number | null;
  duration_ms: number | null;
  user_email: string | null;
  error_message: string | null;
  created_at: string;
}

export interface UptimeApiLogList {
  items: UptimeApiLogItem[];
  total: number;
}

export interface UptimeClientDashboard {
  subscription: UptimeSubscription | null;
  package: UptimePackage | null;
  quota_monitors: UptimeMeter;
  quota_alert_contacts: UptimeMeter;
  quota_maintenance_windows: UptimeMeter;
  quota_status_pages: UptimeMeter;
}

// ---------- admin ----------
const ADMIN_BASE = "/api/v1/admin/uptimerobot";
const CLIENT_BASE = "/api/v1/uptimerobot";

export async function adminListPackages(): Promise<UptimePackage[]> {
  const res = await fetch(`${ADMIN_BASE}/packages`, { headers: authHeaders() });
  return handle<UptimePackage[]>(res);
}

export async function adminCreatePackage(
  payload: UptimePackageInput,
): Promise<UptimePackage> {
  const res = await fetch(`${ADMIN_BASE}/packages`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimePackage>(res);
}

export async function adminUpdatePackage(
  id: number,
  payload: Partial<UptimePackageInput>,
): Promise<UptimePackage> {
  const res = await fetch(`${ADMIN_BASE}/packages/${id}`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimePackage>(res);
}

export async function adminDeletePackage(id: number): Promise<void> {
  const res = await fetch(`${ADMIN_BASE}/packages/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    await handle(res);
  }
}

export async function adminListSubscriptions(filters?: {
  status?: string;
  user_id?: string;
}): Promise<UptimeSubscription[]> {
  const q = new URLSearchParams();
  if (filters?.status) q.set("status", filters.status);
  if (filters?.user_id) q.set("user_id", filters.user_id);
  const url = q.toString()
    ? `${ADMIN_BASE}/subscriptions?${q}`
    : `${ADMIN_BASE}/subscriptions`;
  const res = await fetch(url, { headers: authHeaders() });
  return handle<UptimeSubscription[]>(res);
}

export async function adminCreateSubscription(payload: {
  user_id: string;
  user_email?: string;
  package_id: number;
  whmcs_service_id?: number;
  whmcs_product_id?: number;
  notes?: string;
}): Promise<UptimeSubscription> {
  const res = await fetch(`${ADMIN_BASE}/subscriptions`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeSubscription>(res);
}

export async function adminUpdateSubscription(
  id: number,
  payload: {
    package_id?: number;
    status?: "active" | "suspended" | "terminated";
    notes?: string;
  },
): Promise<UptimeSubscription> {
  const res = await fetch(`${ADMIN_BASE}/subscriptions/${id}`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeSubscription>(res);
}

export async function adminSuspendSubscription(
  id: number,
): Promise<UptimeSubscription> {
  const res = await fetch(`${ADMIN_BASE}/subscriptions/${id}/suspend`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeSubscription>(res);
}

export async function adminResumeSubscription(
  id: number,
): Promise<UptimeSubscription> {
  const res = await fetch(`${ADMIN_BASE}/subscriptions/${id}/resume`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeSubscription>(res);
}

export async function adminTerminateSubscription(
  id: number,
): Promise<UptimeSubscription> {
  const res = await fetch(`${ADMIN_BASE}/subscriptions/${id}/terminate`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeSubscription>(res);
}

export async function adminListSubscriptionMonitors(
  subscriptionId: number,
): Promise<UptimeMonitor[]> {
  const res = await fetch(
    `${ADMIN_BASE}/subscriptions/${subscriptionId}/monitors`,
    { headers: authHeaders() },
  );
  return handle<UptimeMonitor[]>(res);
}

export async function adminGetTeamUsage(): Promise<UptimeTeamUsage> {
  const res = await fetch(`${ADMIN_BASE}/usage`, { headers: authHeaders() });
  return handle<UptimeTeamUsage>(res);
}

export async function adminGetApiSettings(): Promise<UptimeApiSettings> {
  const res = await fetch(`${ADMIN_BASE}/api-settings`, { headers: authHeaders() });
  return handle<UptimeApiSettings>(res);
}

export async function adminSaveApiKey(apiKey: string): Promise<UptimeApiSettings> {
  const res = await fetch(`${ADMIN_BASE}/api-settings/key`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ api_key: apiKey }),
  });
  return handle<UptimeApiSettings>(res);
}

export async function adminTestApiKey(): Promise<UptimeApiTestResult> {
  const res = await fetch(`${ADMIN_BASE}/api-settings/test`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeApiTestResult>(res);
}

export async function adminSyncNow(): Promise<UptimeSyncResult> {
  const res = await fetch(`${ADMIN_BASE}/sync-now`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeSyncResult>(res);
}

export async function adminListApiLogs(params?: {
  limit?: number;
  offset?: number;
  status?: string;
  q?: string;
}): Promise<UptimeApiLogList> {
  const q = new URLSearchParams();
  q.set("limit", String(params?.limit ?? 50));
  q.set("offset", String(params?.offset ?? 0));
  if (params?.status) q.set("status", params.status);
  if (params?.q) q.set("q", params.q);
  const res = await fetch(`${ADMIN_BASE}/api-logs?${q}`, { headers: authHeaders() });
  return handle<UptimeApiLogList>(res);
}

// ---------- client ----------
export async function clientGetDashboard(): Promise<UptimeClientDashboard> {
  const res = await fetch(`${CLIENT_BASE}/subscription`, { headers: authHeaders() });
  return handle<UptimeClientDashboard>(res);
}

export async function clientListAvailablePackages(): Promise<UptimePackage[]> {
  const res = await fetch(`${CLIENT_BASE}/packages`, { headers: authHeaders() });
  return handle<UptimePackage[]>(res);
}

export async function clientActivateSubscription(
  packageId: number,
): Promise<UptimeClientDashboard> {
  const res = await fetch(`${CLIENT_BASE}/subscription/activate`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ package_id: packageId }),
  });
  return handle<UptimeClientDashboard>(res);
}

export async function clientListMonitors(): Promise<UptimeMonitor[]> {
  const res = await fetch(`${CLIENT_BASE}/monitors`, { headers: authHeaders() });
  return handle<UptimeMonitor[]>(res);
}

export async function clientCreateMonitor(payload: {
  friendly_name: string;
  monitor_type: "http" | "ping" | "port" | "keyword" | "heartbeat";
  url?: string;
  keyword?: string;
  port?: number;
  interval_seconds: number;
}): Promise<UptimeMonitor> {
  const res = await fetch(`${CLIENT_BASE}/monitors`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeMonitor>(res);
}

export async function clientUpdateMonitor(
  id: number,
  payload: {
    friendly_name?: string;
    url?: string;
    keyword?: string;
    port?: number;
    interval_seconds?: number;
  },
): Promise<UptimeMonitor> {
  const res = await fetch(`${CLIENT_BASE}/monitors/${id}`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeMonitor>(res);
}

export async function clientPauseMonitor(id: number): Promise<UptimeMonitor> {
  const res = await fetch(`${CLIENT_BASE}/monitors/${id}/pause`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeMonitor>(res);
}

export async function clientResumeMonitor(id: number): Promise<UptimeMonitor> {
  const res = await fetch(`${CLIENT_BASE}/monitors/${id}/resume`, {
    method: "POST",
    headers: authHeaders(),
  });
  return handle<UptimeMonitor>(res);
}

export async function clientDeleteMonitor(id: number): Promise<void> {
  const res = await fetch(`${CLIENT_BASE}/monitors/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    await handle(res);
  }
}

export async function clientMonitorLogs(id: number, limit = 20): Promise<unknown> {
  const res = await fetch(`${CLIENT_BASE}/monitors/${id}/logs?limit=${limit}`, {
    headers: authHeaders(),
  });
  return handle<unknown>(res);
}

// Email alert preferences (status-change notifications).
export interface UptimeNotificationPref {
  email_notifications_enabled: boolean;
  notify_email: string | null;
}

export async function clientGetNotificationPrefs(): Promise<UptimeNotificationPref> {
  const res = await fetch(`${CLIENT_BASE}/notification-preferences`, {
    headers: authHeaders(),
  });
  return handle<UptimeNotificationPref>(res);
}

export async function clientUpdateNotificationPrefs(
  enabled: boolean,
): Promise<UptimeNotificationPref> {
  const res = await fetch(`${CLIENT_BASE}/notification-preferences`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify({ email_notifications_enabled: enabled }),
  });
  return handle<UptimeNotificationPref>(res);
}

export async function clientListAlertContacts(): Promise<UptimeAlertContact[]> {
  const res = await fetch(`${CLIENT_BASE}/alert-contacts`, { headers: authHeaders() });
  return handle<UptimeAlertContact[]>(res);
}

export async function clientCreateAlertContact(payload: {
  contact_type: "email" | "sms" | "webhook" | "slack" | "telegram";
  value: string;
  friendly_name?: string;
}): Promise<UptimeAlertContact> {
  const res = await fetch(`${CLIENT_BASE}/alert-contacts`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeAlertContact>(res);
}

export async function clientDeleteAlertContact(id: number): Promise<void> {
  const res = await fetch(`${CLIENT_BASE}/alert-contacts/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    await handle(res);
  }
}

export async function clientListMaintenanceWindows(): Promise<UptimeMaintenanceWindow[]> {
  const res = await fetch(`${CLIENT_BASE}/maintenance-windows`, { headers: authHeaders() });
  return handle<UptimeMaintenanceWindow[]>(res);
}

export async function clientCreateMaintenanceWindow(payload: {
  friendly_name: string;
  window_type: "once" | "daily" | "weekly" | "monthly";
  start_time?: string;
  duration_minutes: number;
}): Promise<UptimeMaintenanceWindow> {
  const res = await fetch(`${CLIENT_BASE}/maintenance-windows`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeMaintenanceWindow>(res);
}

export async function clientDeleteMaintenanceWindow(id: number): Promise<void> {
  const res = await fetch(`${CLIENT_BASE}/maintenance-windows/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    await handle(res);
  }
}

export async function clientListStatusPages(): Promise<UptimeStatusPage[]> {
  const res = await fetch(`${CLIENT_BASE}/status-pages`, { headers: authHeaders() });
  return handle<UptimeStatusPage[]>(res);
}

export async function clientCreateStatusPage(payload: {
  friendly_name: string;
  custom_url?: string;
  monitor_ids: string[];
}): Promise<UptimeStatusPage> {
  const res = await fetch(`${CLIENT_BASE}/status-pages`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UptimeStatusPage>(res);
}

export async function clientDeleteStatusPage(id: number): Promise<void> {
  const res = await fetch(`${CLIENT_BASE}/status-pages/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    await handle(res);
  }
}

// ---------- shared UI helpers ----------
export function warningTone(state: UptimeWarningState): {
  bg: string;
  text: string;
  border: string;
  bar: string;
} {
  switch (state) {
    case "upgrade_required":
      return {
        bg: "bg-red-50",
        text: "text-red-700",
        border: "border-red-200",
        bar: "bg-red-500",
      };
    case "critical_95":
      return {
        bg: "bg-red-50",
        text: "text-red-700",
        border: "border-red-200",
        bar: "bg-red-500",
      };
    case "warn_85":
      return {
        bg: "bg-orange-50",
        text: "text-orange-700",
        border: "border-orange-200",
        bar: "bg-orange-500",
      };
    case "warn_70":
      return {
        bg: "bg-amber-50",
        text: "text-amber-700",
        border: "border-amber-200",
        bar: "bg-amber-500",
      };
    default:
      return {
        bg: "bg-emerald-50",
        text: "text-emerald-700",
        border: "border-emerald-200",
        bar: "bg-emerald-500",
      };
  }
}

export function percentOf(meter: UptimeMeter): number {
  if (meter.unlimited) return 0;
  if (!meter.total || meter.total <= 0) return 0;
  return Math.min(100, Math.round((meter.used / meter.total) * 100));
}

export function meterTone(meter: UptimeMeter): ReturnType<typeof warningTone> {
  const pct = percentOf(meter);
  if (meter.unlimited) return warningTone("ok");
  if (pct >= 100) return warningTone("upgrade_required");
  if (pct >= 95) return warningTone("critical_95");
  if (pct >= 85) return warningTone("warn_85");
  if (pct >= 70) return warningTone("warn_70");
  return warningTone("ok");
}