import { describe, it, expect, vi, beforeEach } from "vitest";

const { mockPlanFindFirst, mockMemberFindFirst } = vi.hoisted(() => ({
  mockPlanFindFirst: vi.fn(),
  mockMemberFindFirst: vi.fn(),
}));

vi.mock("@epicure/db", () => ({
  db: {
    query: {
      mealPlans: { findFirst: mockPlanFindFirst },
      mealPlanMembers: { findFirst: mockMemberFindFirst },
    },
  },
  mealPlans: { id: "id", userId: "user_id" },
  mealPlanMembers: { mealPlanId: "meal_plan_id", userId: "user_id" },
  eq: vi.fn((a, b) => ({ a, b, op: "eq" })),
  and: vi.fn((...args) => ({ args, op: "and" })),
}));

const { getMealPlanAccessById, canWriteMealPlan } = await import("../meal-plan-access");

beforeEach(() => {
  vi.clearAllMocks();
});

describe("getMealPlanAccessById", () => {
  it("returns null when the plan doesn't exist", async () => {
    mockPlanFindFirst.mockResolvedValue(undefined);
    expect(await getMealPlanAccessById("plan-1", "user-1")).toBeNull();
  });

  it("grants owner role to the plan's userId", async () => {
    mockPlanFindFirst.mockResolvedValue({ id: "plan-1", userId: "user-1" });
    const access = await getMealPlanAccessById("plan-1", "user-1");
    expect(access?.role).toBe("owner");
  });

  it("grants the member's assigned role", async () => {
    mockPlanFindFirst.mockResolvedValue({ id: "plan-1", userId: "user-owner" });
    mockMemberFindFirst.mockResolvedValue({ role: "viewer" });
    const access = await getMealPlanAccessById("plan-1", "user-2");
    expect(access?.role).toBe("viewer");
  });

  it("returns null when the user is neither owner nor a member", async () => {
    mockPlanFindFirst.mockResolvedValue({ id: "plan-1", userId: "user-owner" });
    mockMemberFindFirst.mockResolvedValue(undefined);
    expect(await getMealPlanAccessById("plan-1", "user-2")).toBeNull();
  });
});

describe("canWriteMealPlan", () => {
  it("allows owner and editor, denies viewer", () => {
    expect(canWriteMealPlan("owner")).toBe(true);
    expect(canWriteMealPlan("editor")).toBe(true);
    expect(canWriteMealPlan("viewer")).toBe(false);
  });
});
