jest.mock("../../src/services/apiClient", () => {
  class ApiClientError extends Error {
    status?: number;
    constructor(message: string, status?: number) {
      super(message);
      this.name = "ApiClientError";
      this.status = status;
    }
  }
  return {
    __esModule: true,
    default: { get: jest.fn(), post: jest.fn() },
    ApiClientError,
  };
});

import apiClient, { ApiClientError } from "../../src/services/apiClient";
import { getMyBottles, postBottleAction } from "../../src/services/bottlesApi";

const get = apiClient.get as jest.Mock;
const post = apiClient.post as jest.Mock;

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

  it("retourne available + bottles quand l'endpoint repond", async () => {
    get.mockResolvedValue({
      data: {
        success: true,
        data: {
          bottles: [{ id: 1, code_interne: "ABC123", type: "gaz", statut: "en_service" }],
          count: 1,
          quota: 10,
          technicien_id: 7,
        },
      },
    });

    const res = await getMyBottles();

    expect(get).toHaveBeenCalledWith("/mobile/bottles.php");
    expect(res.available).toBe(true);
    if (res.available) {
      expect(res.payload.bottles).toHaveLength(1);
      expect(res.payload.count).toBe(1);
      expect(res.payload.quota).toBe(10);
      expect(res.payload.technicien_id).toBe(7);
    }
  });

  it("degrade en available:false quand l'endpoint est absent (404)", async () => {
    get.mockRejectedValue(new ApiClientError("HTTP 404", 404));

    const res = await getMyBottles();

    expect(res.available).toBe(false);
  });

  it("propage les autres erreurs reseau (500)", async () => {
    get.mockRejectedValue(new ApiClientError("HTTP 500", 500));

    await expect(getMyBottles()).rejects.toThrow();
  });

  it("leve quand le backend renvoie success=false", async () => {
    get.mockResolvedValue({ data: { success: false, message: "boom" } });

    await expect(getMyBottles()).rejects.toThrow("boom");
  });

  it("normalise un bottles non-array en tableau vide", async () => {
    get.mockResolvedValue({
      data: { success: true, data: { bottles: null, count: 0, quota: 10, technicien_id: 1 } },
    });

    const res = await getMyBottles();

    expect(res.available).toBe(true);
    if (res.available) {
      expect(res.payload.bottles).toEqual([]);
    }
  });
});

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

  it("envoie action + bottle_id + extra et resout sur success", async () => {
    post.mockResolvedValue({ data: { success: true, data: {} } });

    await postBottleAction("request_return", 42, { commentaire: "RAS" });

    expect(post).toHaveBeenCalledWith("/mobile/bottle_action.php", {
      action: "request_return",
      bottle_id: 42,
      commentaire: "RAS",
    });
  });

  it("leve avec le message metier quand success=false (mauvais statut)", async () => {
    post.mockResolvedValue({ data: { success: false, message: "statut invalide" } });

    await expect(postBottleAction("confirm_drop", 7)).rejects.toThrow("statut invalide");
  });

  it("echange : transmet numero_serie_nouvelle + type_nouvelle", async () => {
    post.mockResolvedValue({ data: { success: true, data: {} } });

    await postBottleAction("exchange", 12, {
      numero_serie_nouvelle: "FR-2024-00123",
      type_nouvelle: "gaz",
    });

    expect(post).toHaveBeenCalledWith("/mobile/bottle_action.php", {
      action: "exchange",
      bottle_id: 12,
      numero_serie_nouvelle: "FR-2024-00123",
      type_nouvelle: "gaz",
    });
  });
});
