import { recordCrash } from "./crashLog";

// Installe les capteurs globaux d'erreurs JS. A appeler UNE seule fois, le plus
// tot possible (au chargement du module App), avant tout rendu. Voir
// OBSERVABILITE_CRASH.md (approche A, §3). Zero dependance externe.

type GlobalErrorHandler = (error: unknown, isFatal?: boolean) => void;

type ErrorUtilsLike = {
  getGlobalHandler?: () => GlobalErrorHandler | undefined;
  setGlobalHandler?: (handler: GlobalErrorHandler) => void;
};

let installed = false;

function toError(value: unknown): Error {
  return value instanceof Error ? value : new Error(String(value));
}

function installGlobalErrorHandler(): void {
  const errorUtils = (globalThis as unknown as { ErrorUtils?: ErrorUtilsLike }).ErrorUtils;
  if (!errorUtils?.setGlobalHandler) {
    return;
  }
  // On CHAINE le handler precedent : on ne casse ni l'ecran rouge de dev ni le
  // comportement de crash natif en prod, on ne fait que journaliser au passage.
  const previous = errorUtils.getGlobalHandler?.();
  errorUtils.setGlobalHandler((error, isFatal) => {
    const err = toError(error);
    void recordCrash({ kind: "fatal", message: err.message, stack: err.stack, isFatal });
    previous?.(error, isFatal);
  });
}

function installRejectionTracking(): void {
  // Best-effort : le suivi des rejets de promesse non geres depend du polyfill
  // "promise" embarque par React Native. Absent dans certains environnements
  // (ex. Jest) -> on ignore, les exceptions fatales restent captees.
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const tracking = require("promise/setimmediate/rejection-tracking") as {
      enable: (options: {
        allRejections?: boolean;
        onUnhandled?: (id: number, error: unknown) => void;
        onHandled?: (id: number) => void;
      }) => void;
    };
    tracking.enable({
      allRejections: true,
      onUnhandled: (_id, error) => {
        const err = toError(error);
        void recordCrash({ kind: "rejection", message: err.message, stack: err.stack });
      },
      onHandled: () => {},
    });
  } catch {
    // Module indisponible : suivi des rejets non installe (sans incidence sur le reste).
  }
}

export function installCrashHandlers(): void {
  if (installed) {
    return;
  }
  installed = true;
  installGlobalErrorHandler();
  installRejectionTracking();
}

// Reservoir de test uniquement : permet de reinstaller les handlers entre tests.
export function __resetCrashHandlersForTests(): void {
  installed = false;
}
