import { env } from "../config/env";

// Client minimal pour l'API Evolution (WhatsApp), en local. Toutes les requêtes portent l'apikey.
const BASE = env.evolution.url.replace(/\/$/, "");
const INSTANCE = env.evolution.instance;

export function isWhatsappConfigured(): boolean {
  return Boolean(env.evolution.apiKey);
}

async function evo(path: string, init?: RequestInit): Promise<Response> {
  return fetch(`${BASE}${path}`, {
    ...init,
    headers: {
      apikey: env.evolution.apiKey,
      "Content-Type": "application/json",
      ...(init?.headers ?? {}),
    },
  });
}

async function evoJson<T = unknown>(path: string, init?: RequestInit): Promise<T> {
  const res = await evo(path, init);
  if (!res.ok) {
    const body = await res.text().catch(() => "");
    throw new Error(`Evolution ${path} → ${res.status} ${body.slice(0, 200)}`);
  }
  return (await res.json().catch(() => ({}))) as T;
}

// S'assure que l'instance existe (création idempotente).
export async function ensureInstance(): Promise<void> {
  const list = await evoJson<Array<{ name?: string; instanceName?: string }>>(
    "/instance/fetchInstances"
  ).catch(() => []);
  const exists = Array.isArray(list) && list.some((i) => (i.name ?? i.instanceName) === INSTANCE);
  if (!exists) {
    await evoJson("/instance/create", {
      method: "POST",
      body: JSON.stringify({ instanceName: INSTANCE, qrcode: true, integration: "WHATSAPP-BAILEYS" }),
    });
  }
}

export interface WhatsappState {
  state: string; // "open" (connecté), "connecting", "close"
  connected: boolean;
}

export async function getState(): Promise<WhatsappState> {
  try {
    const d = await evoJson<{ instance?: { state?: string } }>(
      `/instance/connectionState/${INSTANCE}`
    );
    const state = d?.instance?.state ?? "close";
    return { state, connected: state === "open" };
  } catch {
    return { state: "close", connected: false };
  }
}

// Renvoie le QR (base64 data-URI) à scanner pour lier le numéro. Crée l'instance au besoin.
export async function getQrCode(): Promise<{ base64: string | null; state: string }> {
  await ensureInstance();
  const st = await getState();
  if (st.connected) return { base64: null, state: "open" };
  const d = await evoJson<{ base64?: string; code?: string }>(`/instance/connect/${INSTANCE}`);
  return { base64: d?.base64 ?? null, state: st.state };
}

export async function logout(): Promise<void> {
  await evo(`/instance/logout/${INSTANCE}`, { method: "DELETE" }).catch(() => {});
}

// Liste des conversations.
export async function findChats(): Promise<unknown[]> {
  const d = await evoJson<unknown>(`/chat/findChats/${INSTANCE}`, {
    method: "POST",
    body: JSON.stringify({}),
  });
  if (Array.isArray(d)) return d;
  const rec = (d as { records?: unknown[] })?.records;
  return Array.isArray(rec) ? rec : [];
}

// Messages d'une conversation (par remoteJid).
export async function findMessages(remoteJid: string): Promise<unknown[]> {
  const d = await evoJson<unknown>(`/chat/findMessages/${INSTANCE}`, {
    method: "POST",
    body: JSON.stringify({ where: { key: { remoteJid } } }),
  });
  // Réponses possibles : tableau, {records:[]}, ou {messages:{records:[]}}
  if (Array.isArray(d)) return d;
  const direct = (d as { records?: unknown[] })?.records;
  if (Array.isArray(direct)) return direct;
  const nested = (d as { messages?: { records?: unknown[] } })?.messages?.records;
  return Array.isArray(nested) ? nested : [];
}

export async function sendText(number: string, text: string): Promise<void> {
  const body = JSON.stringify({ number, text });
  const path = `/message/sendText/${INSTANCE}`;
  // Le socket Baileys peut se fermer brièvement (reconnexion) → plusieurs essais avec backoff.
  const delays = [0, 2000, 4000];
  let lastErr: unknown;
  for (const d of delays) {
    if (d) await new Promise((r) => setTimeout(r, d));
    try {
      await evoJson(path, { method: "POST", body });
      return;
    } catch (e) {
      lastErr = e;
    }
  }
  throw lastErr;
}
