jest.mock("../models/list.model.v2", () => ({
  addHistoryRecord: jest.fn(),
  addOrUpdateItem: jest.fn(),
}));

jest.mock("../models/household.model", () => ({
  isHouseholdMember: jest.fn(),
}));

jest.mock("../utils/logger", () => ({
  logError: jest.fn(),
}));

const List = require("../models/list.model.v2");
const householdModel = require("../models/household.model");
const controller = require("../controllers/lists.controller.v2");

function createResponse() {
  const res = {};
  res.status = jest.fn().mockReturnValue(res);
  res.json = jest.fn().mockReturnValue(res);
  return res;
}

describe("lists.controller.v2 addItem", () => {
  beforeEach(() => {
    List.addOrUpdateItem.mockResolvedValue({
      listId: 42,
      itemName: "milk",
      isNew: true,
    });
    List.addHistoryRecord.mockResolvedValue(undefined);
    householdModel.isHouseholdMember.mockResolvedValue(true);
  });

  test("records history for selected added_for_user_id when member is valid", async () => {
    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1", added_for_user_id: "9" },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(householdModel.isHouseholdMember).toHaveBeenCalledWith("1", 9);
    expect(List.addOrUpdateItem).toHaveBeenCalled();
    expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 9);
    expect(res.status).not.toHaveBeenCalledWith(400);
  });

  test("records history using request user when added_for_user_id is not provided", async () => {
    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1" },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(householdModel.isHouseholdMember).not.toHaveBeenCalled();
    expect(List.addOrUpdateItem).toHaveBeenCalled();
    expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 7);
    expect(res.status).not.toHaveBeenCalledWith(400);
  });

  test("records history using request user when added_for_user_id is blank", async () => {
    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1", added_for_user_id: "   " },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(householdModel.isHouseholdMember).not.toHaveBeenCalled();
    expect(List.addOrUpdateItem).toHaveBeenCalled();
    expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 7);
    expect(res.status).not.toHaveBeenCalledWith(400);
  });

  test("rejects invalid added_for_user_id", async () => {
    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1", added_for_user_id: "abc" },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(List.addOrUpdateItem).not.toHaveBeenCalled();
    expect(List.addHistoryRecord).not.toHaveBeenCalled();
    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledWith(
      expect.objectContaining({
        error: expect.objectContaining({
          message: "Added-for user ID must be a positive integer",
        }),
      })
    );
  });

  test("rejects malformed numeric-looking added_for_user_id", async () => {
    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1", added_for_user_id: "9abc" },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(List.addOrUpdateItem).not.toHaveBeenCalled();
    expect(List.addHistoryRecord).not.toHaveBeenCalled();
    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledWith(
      expect.objectContaining({
        error: expect.objectContaining({
          message: "Added-for user ID must be a positive integer",
        }),
      })
    );
  });

  test("rejects added_for_user_id when target user is not household member", async () => {
    householdModel.isHouseholdMember.mockResolvedValue(false);

    const req = {
      params: { householdId: "1", storeId: "2" },
      body: { item_name: "milk", quantity: "1", added_for_user_id: "11" },
      user: { id: 7 },
      processedImage: null,
    };
    const res = createResponse();

    await controller.addItem(req, res);

    expect(householdModel.isHouseholdMember).toHaveBeenCalledWith("1", 11);
    expect(List.addOrUpdateItem).not.toHaveBeenCalled();
    expect(List.addHistoryRecord).not.toHaveBeenCalled();
    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledWith(
      expect.objectContaining({
        error: expect.objectContaining({
          message: "Selected user is not a member of this household",
        }),
      })
    );
  });
});
