// @File: src/lib/adminApi.ts
// @Desc: Thin typed fetch helpers for the admin CMS pages that talk to the
//        local-auth / admin-users endpoints. These endpoints expect an app
//        JWT in the `Authorization: Bearer <token>` header. We read the
//        token from localStorage (key `token`), matching lib/auth.ts.
import { getToken } from "@/lib/auth";

export interface AdminUserRow {
  id: string;
  email: string;
  name: string | null;
  role: "admin" | "user" | string;
  auth_provider: "local" | "platform" | string;
  is_active: boolean;
  last_login: string | null;
  created_at: string | null;
}

export interface AdminUserList {
  items: AdminUserRow[];
  total: number;
  page: number;
  page_size: number;
}

export interface LocalAuthResponse {
  token: string;
  token_type: string;
  user_id: string;
  email: string;
  role: string;
}

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;
}

// Response from /auth/local/login: either a session token (LocalAuthResponse)
// or an mfa_required envelope that needs a challenge/verify roundtrip.
export interface LoginMfaRequired {
  mfa_required: true;
  mfa_token: string;
  phone_masked: string | null;
  expires_in_seconds: number;
  message: string;
}

export type LoginResponse = LocalAuthResponse | LoginMfaRequired;

export function isMfaRequired(value: LoginResponse): value is LoginMfaRequired {
  return (value as LoginMfaRequired).mfa_required === true;
}

export async function adminLoginLocal(email: string, password: string): Promise<LoginResponse> {
  const res = await fetch("/api/v1/auth/local/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  });
  return handleJson<LoginResponse>(res);
}

// ---------------------------------------------------------------------------
// MFA (SMS) — shared between user settings and login challenge
// ---------------------------------------------------------------------------

export interface MfaStatus {
  enabled: boolean;
  method: string;
  phone_masked: string | null;
  last_verified_at: string | null;
}

export interface MfaSetupStartResponse {
  ok: boolean;
  message: string;
  phone_masked: string | null;
  expires_in_seconds: number;
}

export interface MfaGenericResponse {
  ok: boolean;
  message: string;
}

export interface MfaAdminEnforcement {
  require_admin_mfa: boolean;
}

export interface MfaAdminRosterEntry {
  user_id: string;
  email: string;
  name: string | null;
  enabled: boolean;
  phone_masked: string | null;
  last_verified_at: string | null;
}

export async function mfaGetStatus(): Promise<MfaStatus> {
  const res = await fetch("/api/v1/auth/mfa/status", { headers: authHeaders() });
  return handleJson<MfaStatus>(res);
}

export async function mfaStartSetup(phoneE164: string): Promise<MfaSetupStartResponse> {
  const res = await fetch("/api/v1/auth/mfa/setup", {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ phone_e164: phoneE164 }),
  });
  return handleJson<MfaSetupStartResponse>(res);
}

export async function mfaVerifySetup(code: string): Promise<MfaStatus> {
  const res = await fetch("/api/v1/auth/mfa/setup/verify", {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ code }),
  });
  return handleJson<MfaStatus>(res);
}

export async function mfaDisable(password: string): Promise<MfaStatus> {
  const res = await fetch("/api/v1/auth/mfa/disable", {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ password }),
  });
  return handleJson<MfaStatus>(res);
}

export async function mfaChallengeSend(mfaToken: string): Promise<MfaGenericResponse> {
  const res = await fetch("/api/v1/auth/mfa/challenge/send", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ mfa_token: mfaToken }),
  });
  return handleJson<MfaGenericResponse>(res);
}

export async function mfaChallengeVerify(
  mfaToken: string,
  code: string,
): Promise<LocalAuthResponse> {
  const res = await fetch("/api/v1/auth/mfa/challenge/verify", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ mfa_token: mfaToken, code }),
  });
  return handleJson<LocalAuthResponse>(res);
}

export async function mfaAdminGetEnforcement(): Promise<MfaAdminEnforcement> {
  const res = await fetch("/api/v1/auth/mfa/admin/enforcement", {
    headers: authHeaders(),
  });
  return handleJson<MfaAdminEnforcement>(res);
}

export async function mfaAdminSetEnforcement(value: boolean): Promise<MfaAdminEnforcement> {
  const res = await fetch("/api/v1/auth/mfa/admin/enforcement", {
    method: "PUT",
    headers: authHeaders(),
    body: JSON.stringify({ require_admin_mfa: value }),
  });
  return handleJson<MfaAdminEnforcement>(res);
}

export async function mfaAdminRoster(): Promise<MfaAdminRosterEntry[]> {
  const res = await fetch("/api/v1/auth/mfa/admin/roster", {
    headers: authHeaders(),
  });
  return handleJson<MfaAdminRosterEntry[]>(res);
}

export async function requestPasswordReset(email: string): Promise<{ detail: string }> {
  const res = await fetch("/api/v1/auth/local/forgot-password", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email }),
  });
  return handleJson<{ detail: string }>(res);
}

export async function confirmPasswordReset(
  token: string,
  newPassword: string,
): Promise<{ detail: string }> {
  const res = await fetch("/api/v1/auth/local/reset-password", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ token, new_password: newPassword }),
  });
  return handleJson<{ detail: string }>(res);
}

export async function listAdminUsers(params: {
  search?: string;
  role?: "admin" | "user" | "";
  provider?: "local" | "platform" | "";
  page?: number;
  pageSize?: number;
}): Promise<AdminUserList> {
  const qs = new URLSearchParams();
  if (params.search) qs.set("search", params.search);
  if (params.role) qs.set("role", params.role);
  if (params.provider) qs.set("provider", params.provider);
  if (params.page) qs.set("page", String(params.page));
  if (params.pageSize) qs.set("page_size", String(params.pageSize));
  const res = await fetch(`/api/v1/admin/users?${qs.toString()}`, {
    method: "GET",
    headers: authHeaders(),
  });
  return handleJson<AdminUserList>(res);
}

export async function updateAdminUserRole(
  userId: string,
  role: "admin" | "user",
): Promise<AdminUserRow> {
  const res = await fetch(`/api/v1/admin/users/${encodeURIComponent(userId)}/role`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify({ role }),
  });
  return handleJson<AdminUserRow>(res);
}

export async function updateAdminUserActive(
  userId: string,
  isActive: boolean,
): Promise<AdminUserRow> {
  const res = await fetch(`/api/v1/admin/users/${encodeURIComponent(userId)}/active`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify({ is_active: isActive }),
  });
  return handleJson<AdminUserRow>(res);
}

export async function adminResetLocalUserPassword(
  userId: string,
  newPassword: string,
): Promise<{ detail: string }> {
  const res = await fetch(
    `/api/v1/admin/users/${encodeURIComponent(userId)}/reset-password`,
    {
      method: "POST",
      headers: authHeaders(),
      body: JSON.stringify({ new_password: newPassword }),
    },
  );
  return handleJson<{ detail: string }>(res);
}

// ---------------------------------------------------------------------------
// Admin audit log
// ---------------------------------------------------------------------------

export interface AuditLogItem {
  id: number;
  created_at: string;
  action: string;
  admin_user_id: string | null;
  admin_email: string | null;
  target_user_id: string | null;
  target_email: string | null;
  details: string | null;
  ip_address: string | null;
  user_agent: string | null;
}

export interface AuditLogList {
  items: AuditLogItem[];
  total: number;
  page: number;
  page_size: number;
  known_actions: string[];
}

export async function listAuditLogs(params: {
  action?: string;
  start?: string;
  end?: string;
  search?: string;
  page?: number;
  pageSize?: number;
}): Promise<AuditLogList> {
  const qs = new URLSearchParams();
  if (params.action) qs.set("action", params.action);
  if (params.start) qs.set("start", params.start);
  if (params.end) qs.set("end", params.end);
  if (params.search) qs.set("search", params.search);
  if (params.page) qs.set("page", String(params.page));
  if (params.pageSize) qs.set("page_size", String(params.pageSize));
  const res = await fetch(`/api/v1/admin/audit-logs?${qs.toString()}`, {
    method: "GET",
    headers: authHeaders(),
  });
  return handleJson<AuditLogList>(res);
}

// ---------- Frontend-cache admin API ----------
export interface CacheConfig {
  enabled: boolean;
  last_cleared_at: number | null;
  cache_version: number;
}

export async function getCacheConfig(): Promise<CacheConfig> {
  const res = await fetch("/api/v1/admin/cache", {
    method: "GET",
    headers: authHeaders(),
  });
  return handleJson<CacheConfig>(res);
}

export async function toggleCacheEnabled(enabled: boolean): Promise<CacheConfig> {
  const res = await fetch("/api/v1/admin/cache/toggle", {
    method: "PUT",
    headers: authHeaders(),
    body: JSON.stringify({ enabled }),
  });
  return handleJson<CacheConfig>(res);
}

export async function clearCache(reason?: string): Promise<CacheConfig> {
  const res = await fetch("/api/v1/admin/cache/clear", {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify({ reason: reason ?? null }),
  });
  return handleJson<CacheConfig>(res);
}

// ---------------------------------------------------------------------------
// Visitor Monitor
// ---------------------------------------------------------------------------

export interface VmOverview {
  total_visits: number;
  unique_visitors: number;
  campaign_clicks: number;
  referral_clicks: number;
  conversion_rate: number;
  active_now: number;
}

export interface VmSessionItem {
  id: number;
  session_id: string;
  visitor_id: string | null;
  user_id: string | null;
  ip_address: string | null;
  country: string | null;
  city: string | null;
  device: string | null;
  browser: string | null;
  os: string | null;
  referrer: string | null;
  landing_page: string | null;
  current_page: string | null;
  utm_source: string | null;
  utm_medium: string | null;
  utm_campaign: string | null;
  pageview_count: number;
  conversion_stage: string;
  started_at: string;
  last_activity_at: string;
  ended_at: string | null;
  is_online: boolean;
  duration_seconds: number;
}

export interface VmSessionList {
  items: VmSessionItem[];
  total: number;
  page: number;
  page_size: number;
}

export interface VmBucket {
  key: string;
  count: number;
}

export interface VmDaily {
  date: string;
  visits: number;
  unique_visitors: number;
}

export interface VmReport {
  by_day: VmDaily[];
  by_source: VmBucket[];
  by_campaign: VmBucket[];
  by_device: VmBucket[];
  by_browser: VmBucket[];
  by_country: VmBucket[];
}

export interface VmCampaignItem {
  id: number;
  name: string;
  utm_source: string;
  utm_medium: string | null;
  utm_campaign: string;
  utm_term: string | null;
  utm_content: string | null;
  landing_page: string;
  target_url: string | null;
  start_date: string | null;
  end_date: string | null;
  status: "active" | "paused" | "archived" | string;
  notes: string | null;
  created_at: string;
  updated_at: string;
  total_clicks: number;
  unique_visitors: number;
  leads: number;
  signups: number;
  orders: number;
  conversions: number;
  referral_url: string;
}

export interface VmCampaignPayload {
  name: string;
  utm_source: string;
  utm_medium?: string | null;
  utm_campaign: string;
  utm_term?: string | null;
  utm_content?: string | null;
  landing_page?: string;
  target_url?: string | null;
  start_date?: string | null;
  end_date?: string | null;
  status?: "active" | "paused" | "archived";
  notes?: string | null;
}

export interface VmJourneyEvent {
  id: number;
  event_type: string;
  label: string | null;
  page: string | null;
  metadata: Record<string, unknown> | null;
  created_at: string;
}

export interface VmJourney {
  session: VmSessionItem;
  events: VmJourneyEvent[];
}

export interface VmSettings {
  tracking_enabled: boolean;
  retention_days: number;
  excluded_ips: string[];
  exclude_staff: boolean;
  mask_sensitive: boolean;
  updated_at: string | null;
}

const VM_BASE = "/api/v1/admin/visitor-monitor";

export async function vmGetOverview(): Promise<VmOverview> {
  const res = await fetch(`${VM_BASE}/overview`, { headers: authHeaders() });
  return handleJson<VmOverview>(res);
}

export async function vmListSessions(params: {
  onlyOnline?: boolean;
  search?: string;
  country?: string;
  device?: string;
  campaign?: string;
  page?: number;
  pageSize?: number;
}): Promise<VmSessionList> {
  const qs = new URLSearchParams();
  if (params.onlyOnline) qs.set("only_online", "true");
  if (params.search) qs.set("search", params.search);
  if (params.country) qs.set("country", params.country);
  if (params.device) qs.set("device", params.device);
  if (params.campaign) qs.set("utm_campaign", params.campaign);
  if (params.page) qs.set("page", String(params.page));
  if (params.pageSize) qs.set("page_size", String(params.pageSize));
  const res = await fetch(`${VM_BASE}/sessions?${qs.toString()}`, {
    headers: authHeaders(),
  });
  return handleJson<VmSessionList>(res);
}

export async function vmGetJourney(sessionId: string): Promise<VmJourney> {
  const res = await fetch(`${VM_BASE}/sessions/${encodeURIComponent(sessionId)}`, {
    headers: authHeaders(),
  });
  return handleJson<VmJourney>(res);
}

export async function vmGetReport(params: {
  start?: string;
  end?: string;
  campaign?: string;
  source?: string;
  country?: string;
  device?: string;
}): Promise<VmReport> {
  const qs = new URLSearchParams();
  if (params.start) qs.set("start", params.start);
  if (params.end) qs.set("end", params.end);
  if (params.campaign) qs.set("campaign", params.campaign);
  if (params.source) qs.set("source", params.source);
  if (params.country) qs.set("country", params.country);
  if (params.device) qs.set("device", params.device);
  const res = await fetch(`${VM_BASE}/reports?${qs.toString()}`, {
    headers: authHeaders(),
  });
  return handleJson<VmReport>(res);
}

export async function vmListCampaigns(status?: string): Promise<VmCampaignItem[]> {
  const qs = new URLSearchParams();
  if (status) qs.set("status", status);
  const res = await fetch(`${VM_BASE}/campaigns?${qs.toString()}`, {
    headers: authHeaders(),
  });
  return handleJson<VmCampaignItem[]>(res);
}

export async function vmCreateCampaign(payload: VmCampaignPayload): Promise<VmCampaignItem> {
  const res = await fetch(`${VM_BASE}/campaigns`, {
    method: "POST",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handleJson<VmCampaignItem>(res);
}

export async function vmUpdateCampaign(
  id: number,
  payload: Partial<VmCampaignPayload>,
): Promise<VmCampaignItem> {
  const res = await fetch(`${VM_BASE}/campaigns/${id}`, {
    method: "PATCH",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handleJson<VmCampaignItem>(res);
}

export async function vmDeleteCampaign(id: number): Promise<void> {
  const res = await fetch(`${VM_BASE}/campaigns/${id}`, {
    method: "DELETE",
    headers: authHeaders(),
  });
  if (!res.ok && res.status !== 204) {
    throw new Error(`Failed to delete campaign (${res.status})`);
  }
}

export async function vmGetSettings(): Promise<VmSettings> {
  const res = await fetch(`${VM_BASE}/settings`, { headers: authHeaders() });
  return handleJson<VmSettings>(res);
}

export async function vmUpdateSettings(payload: Partial<VmSettings>): Promise<VmSettings> {
  const res = await fetch(`${VM_BASE}/settings`, {
    method: "PUT",
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handleJson<VmSettings>(res);
}