const mockFsState = {
  exists: new Map<string, boolean>(),
  createDir: jest.fn(),
  createFile: jest.fn(),
  copy: jest.fn(),
  write: jest.fn(),
};

jest.mock("expo-file-system", () => {
  class MockDirectory {
    uri: string;
    constructor(parent: string | MockDirectory, name?: string) {
      const base = typeof parent === "string" ? parent : parent.uri;
      this.uri = name ? `${base.replace(/\/$/, "")}/${name}/` : base;
    }
    get exists(): boolean {
      return mockFsState.exists.get(this.uri) ?? false;
    }
    create(opts?: unknown) {
      mockFsState.createDir(this.uri, opts);
      mockFsState.exists.set(this.uri, true);
    }
  }
  class MockFile {
    uri: string;
    constructor(parent: string | MockDirectory, name?: string) {
      const base = typeof parent === "string" ? parent : parent.uri;
      this.uri = name ? `${base.replace(/\/$/, "")}/${name}` : base;
    }
    get exists(): boolean {
      return mockFsState.exists.get(this.uri) ?? false;
    }
    create(opts?: unknown) {
      mockFsState.createFile(this.uri, opts);
    }
    write(data: string, opts?: unknown) {
      mockFsState.write(this.uri, data, opts);
    }
    copy(target: MockFile) {
      mockFsState.copy(this.uri, target.uri);
    }
  }
  return {
    Directory: MockDirectory,
    File: MockFile,
    Paths: { document: "file:///doc" },
  };
});

import {
  resolveMediaFileUri,
  saveDevisPdfToCacheFile,
  savePhotoToPermanentFile,
  saveSignatureBase64ToPermanentFile,
} from "../../src/core/fileStorage";

describe("fileStorage", () => {
  beforeEach(() => {
    mockFsState.exists.clear();
    mockFsState.createDir.mockClear();
    mockFsState.createFile.mockClear();
    mockFsState.copy.mockClear();
    mockFsState.write.mockClear();
    jest.spyOn(Date, "now").mockReturnValue(1234567890);
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  describe("savePhotoToPermanentFile", () => {
    it("cree le dossier si inexistant et copie le fichier", async () => {
      const uri = await savePhotoToPermanentFile(5, "step-1", "file:///tmp/src.jpg");
      expect(mockFsState.createDir).toHaveBeenCalledWith(
        "file:///doc/workflow-media/",
        expect.objectContaining({ intermediates: true, idempotent: true })
      );
      expect(mockFsState.copy).toHaveBeenCalledWith(
        "file:///tmp/src.jpg",
        "file:///doc/workflow-media/photo_5_step-1_1234567890.jpg"
      );
      expect(uri).toBe("file:///doc/workflow-media/photo_5_step-1_1234567890.jpg");
    });

    it("ne recree pas le dossier s'il existe deja", async () => {
      mockFsState.exists.set("file:///doc/workflow-media/", true);
      await savePhotoToPermanentFile(1, "x", "file:///tmp/x.jpg");
      expect(mockFsState.createDir).not.toHaveBeenCalled();
    });

    it("sanitize stepId avec caracteres speciaux", async () => {
      const uri = await savePhotoToPermanentFile(1, "step/with spaces!", "file:///t");
      expect(uri).toContain("step_with_spaces_");
    });
  });

  describe("saveSignatureBase64ToPermanentFile", () => {
    it("cree le fichier PNG et ecrit le base64", async () => {
      const uri = await saveSignatureBase64ToPermanentFile(7, "sig", "BASE64DATA");
      expect(mockFsState.createFile).toHaveBeenCalledWith(
        "file:///doc/workflow-media/signature_7_sig_1234567890.png",
        { overwrite: true, intermediates: true }
      );
      expect(mockFsState.write).toHaveBeenCalledWith(
        "file:///doc/workflow-media/signature_7_sig_1234567890.png",
        "BASE64DATA",
        { encoding: "base64" }
      );
      expect(uri).toBe("file:///doc/workflow-media/signature_7_sig_1234567890.png");
    });

    it("ne recree pas le dossier si existant", async () => {
      mockFsState.exists.set("file:///doc/workflow-media/", true);
      await saveSignatureBase64ToPermanentFile(1, "s", "B");
      expect(mockFsState.createDir).not.toHaveBeenCalled();
    });
  });

  // M2 : re-resolution de l'URI sur le conteneur courant (chemins iOS instables
  // entre builds).
  describe("resolveMediaFileUri", () => {
    it("rebase l'URI sur le dossier media courant quand le fichier (par nom) existe", () => {
      // Le fichier existe sous le conteneur COURANT, sous le meme nom
      mockFsState.exists.set(
        "file:///doc/workflow-media/photo_5_step_1.jpg",
        true
      );
      // URI figee pointant vers un ANCIEN conteneur (GUID different)
      const stale =
        "file:///var/mobile/Containers/Data/Application/OLD-GUID/Documents/workflow-media/photo_5_step_1.jpg";

      expect(resolveMediaFileUri(stale)).toBe(
        "file:///doc/workflow-media/photo_5_step_1.jpg"
      );
    });

    it("retombe sur l'URI d'origine si le fichier rebase n'existe pas", () => {
      const stored = "file:///doc/workflow-media/inconnue.jpg";
      expect(resolveMediaFileUri(stored)).toBe(stored);
    });

    it("URI vide / sans nom -> renvoyee telle quelle", () => {
      expect(resolveMediaFileUri("")).toBe("");
    });
  });

  describe("saveDevisPdfToCacheFile", () => {
    it("cree le dossier cache si absent, ecrit les octets (overwrite) et renvoie l'URI", () => {
      const bytes = new Uint8Array([37, 80, 68, 70]); // %PDF
      const uri = saveDevisPdfToCacheFile(7, bytes);

      expect(mockFsState.createDir).toHaveBeenCalledWith(
        "file:///doc/devis-cache/",
        expect.objectContaining({ intermediates: true, idempotent: true })
      );
      expect(mockFsState.createFile).toHaveBeenCalledWith(
        "file:///doc/devis-cache/devis_7.pdf",
        expect.objectContaining({ overwrite: true })
      );
      expect(mockFsState.write).toHaveBeenCalledWith(
        "file:///doc/devis-cache/devis_7.pdf",
        bytes,
        undefined
      );
      expect(uri).toBe("file:///doc/devis-cache/devis_7.pdf");
    });

    it("ne recree pas le dossier cache s'il existe deja", () => {
      mockFsState.exists.set("file:///doc/devis-cache/", true);
      saveDevisPdfToCacheFile(3, new Uint8Array([1]));
      expect(mockFsState.createDir).not.toHaveBeenCalled();
    });
  });
});
