import * as SecureStore from "expo-secure-store";
import {
  clearAllPrecheckDrafts,
  clearPrecheckDraft,
  getPrecheckDraft,
  savePrecheckDraft,
} from "../../src/services/precheckDraftStorage";
import type { MobilePrecheckPayload } from "../../src/types/intervention";

const payload: MobilePrecheckPayload = {
  intervention_id: 42,
  cerfa_enabled: true,
} as MobilePrecheckPayload;

describe("precheckDraftStorage", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe("savePrecheckDraft", () => {
    it("stocke le draft et ajoute l'id a l'index", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(null);
      await savePrecheckDraft(payload);

      const calls = (SecureStore.setItemAsync as jest.Mock).mock.calls;
      expect(calls.some((c) => c[0] === "cc_precheck_draft_42")).toBe(true);
      expect(calls.some((c) => c[0] === "cc_precheck_draft_index" && c[1] === "[42]")).toBe(true);
    });

    it("n'ajoute pas un id deja present dans l'index", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(JSON.stringify([42]));
      await savePrecheckDraft(payload);
      const indexCall = (SecureStore.setItemAsync as jest.Mock).mock.calls.find(
        (c) => c[0] === "cc_precheck_draft_index"
      );
      expect(indexCall).toBeUndefined();
    });
  });

  describe("getPrecheckDraft", () => {
    it("retourne null quand rien stocke", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(null);
      expect(await getPrecheckDraft(42)).toBeNull();
    });

    it("retourne le draft parse", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(
        JSON.stringify({ intervention_id: 42, cerfa_enabled: false, saved_at: "2026-01-01" })
      );
      const draft = await getPrecheckDraft(42);
      expect(draft?.intervention_id).toBe(42);
      expect(draft?.cerfa_enabled).toBe(false);
    });

    it("retourne null quand champs requis invalides", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(
        JSON.stringify({ intervention_id: "bad", cerfa_enabled: true })
      );
      expect(await getPrecheckDraft(42)).toBeNull();
    });

    it("retourne null quand JSON corrompu", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue("{bad");
      expect(await getPrecheckDraft(42)).toBeNull();
    });
  });

  describe("clearPrecheckDraft", () => {
    it("supprime le draft et met a jour l'index", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(JSON.stringify([42, 43]));
      await clearPrecheckDraft(42);
      expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith("cc_precheck_draft_42");
      const indexCall = (SecureStore.setItemAsync as jest.Mock).mock.calls.find(
        (c) => c[0] === "cc_precheck_draft_index"
      );
      expect(indexCall?.[1]).toBe("[43]");
    });

    it("supprime l'index quand plus aucun id", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(JSON.stringify([42]));
      await clearPrecheckDraft(42);
      expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith("cc_precheck_draft_index");
    });
  });

  describe("clearAllPrecheckDrafts", () => {
    it("supprime tous les drafts et l'index", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(JSON.stringify([1, 2]));
      await clearAllPrecheckDrafts();
      expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith("cc_precheck_draft_1");
      expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith("cc_precheck_draft_2");
      expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith("cc_precheck_draft_index");
    });
  });

  describe("readIndex — couverture des branches de parsing", () => {
    it("readIndex retourne [] si JSON corrompu (via savePrecheckDraft)", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue("{bad");
      await savePrecheckDraft(payload);
      const indexCall = (SecureStore.setItemAsync as jest.Mock).mock.calls.find(
        (c) => c[0] === "cc_precheck_draft_index"
      );
      expect(indexCall?.[1]).toBe("[42]");
    });

    it("readIndex retourne [] si JSON n'est pas un array", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue('{"foo":"bar"}');
      await savePrecheckDraft(payload);
      const indexCall = (SecureStore.setItemAsync as jest.Mock).mock.calls.find(
        (c) => c[0] === "cc_precheck_draft_index"
      );
      expect(indexCall?.[1]).toBe("[42]");
    });

    it("readIndex filtre les valeurs non-entier ou negatives", async () => {
      (SecureStore.getItemAsync as jest.Mock).mockResolvedValue(
        JSON.stringify([1, -2, "abc", 3.5, 7])
      );
      await savePrecheckDraft(payload);
      const indexCall = (SecureStore.setItemAsync as jest.Mock).mock.calls.find(
        (c) => c[0] === "cc_precheck_draft_index"
      );
      expect(indexCall?.[1]).toBe("[1,7,42]");
    });
  });
});
