jest.mock("../../src/core/crashLog", () => ({
  recordCrash: jest.fn(),
}));

const mockRejectionEnable = jest.fn();
// PAS de { virtual: true } : ce module EXISTE reellement dans node_modules
// (promise/setimmediate/rejection-tracking.js). Avec virtual:true, quand un
// autre fichier de test charge le vrai module avant celui-ci (ex. App.test ->
// installCrashHandlers au scope module de App.tsx), l'interception devenait
// non-deterministe et `enable` reel etait appele -> mockRejectionEnable a 0.
// Un mock normal d'un module existant intercepte de facon fiable, quel que soit
// l'ordre des fichiers.
jest.mock("promise/setimmediate/rejection-tracking", () => ({
  enable: mockRejectionEnable,
}));

import { recordCrash } from "../../src/core/crashLog";
import {
  __resetCrashHandlersForTests,
  installCrashHandlers,
} from "../../src/core/crashHandlers";

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

describe("crashHandlers", () => {
  let setHandler: jest.Mock;
  let previous: jest.Mock;
  let installedHandler: GlobalHandler | undefined;

  beforeEach(() => {
    __resetCrashHandlersForTests();
    jest.clearAllMocks();
    installedHandler = undefined;
    setHandler = jest.fn((handler: GlobalHandler) => {
      installedHandler = handler;
    });
    previous = jest.fn();
    (global as unknown as { ErrorUtils: unknown }).ErrorUtils = {
      getGlobalHandler: () => previous,
      setGlobalHandler: setHandler,
    };
  });

  it("installe un handler global qui journalise et chaine le precedent", () => {
    installCrashHandlers();
    expect(setHandler).toHaveBeenCalledTimes(1);

    const err = new Error("kaboom");
    installedHandler?.(err, true);

    expect(recordCrash).toHaveBeenCalledWith(
      expect.objectContaining({ kind: "fatal", message: "kaboom", isFatal: true })
    );
    expect(previous).toHaveBeenCalledWith(err, true);
  });

  it("convertit une valeur non-Error en Error avant journalisation", () => {
    installCrashHandlers();
    installedHandler?.("string error", false);
    expect(recordCrash).toHaveBeenCalledWith(
      expect.objectContaining({ kind: "fatal", message: "string error" })
    );
  });

  it("active le suivi des rejets de promesse non geres", () => {
    installCrashHandlers();
    expect(mockRejectionEnable).toHaveBeenCalledTimes(1);
    const options = mockRejectionEnable.mock.calls[0][0];
    options.onUnhandled(1, new Error("rej"));
    expect(recordCrash).toHaveBeenCalledWith(
      expect.objectContaining({ kind: "rejection", message: "rej" })
    );
  });

  it("ne s'installe qu'une seule fois", () => {
    installCrashHandlers();
    installCrashHandlers();
    expect(setHandler).toHaveBeenCalledTimes(1);
  });
});
