import type { CommandContext } from "@tailor-platform/erp-kit/core";
import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { InventorySupplyPlanNotFoundError, SupplyPlanNotOpenError } from "../lib/errors.generated";
import { baseSupplyPlan } from "../testing/fixtures";
import { run } from "./closeInventorySupplyPlan";

describe("closeInventorySupplyPlan", () => {
  const ctx: CommandContext = {
    actorId: "test-actor",
    permissions: ["inventory:supplyPlan:closeInventorySupplyPlan"],
  };

  const input = {
    target: "SUPPLY_PLAN" as const,
    id: "supply-plan-1",
  };

  it("closes supply plan by id", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const closed = { ...baseSupplyPlan, status: "CLOSED" };
    spies.select.mockReturnValueOnce(baseSupplyPlan);
    spies.update.mockReturnValueOnce(closed);

    const result = await run(db, input, ctx);

    expect(result.ok).toBe(true);
    if (!result.ok) {
      throw result.error;
    }
    expect(result.value).toHaveProperty("supplyPlan");
    if ("supplyPlan" in result.value) {
      expect(result.value.supplyPlan.status).toBe("CLOSED");
    }
    expect(spies.update).toHaveBeenCalled();
  });

  it("returns error when supply plan not found", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined);

    const result = await run(db, input, ctx);

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InventorySupplyPlanNotFoundError);
    }
  });

  it("returns error when supply plan is closed", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce({ ...baseSupplyPlan, status: "CLOSED" });

    const result = await run(db, input, ctx);

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(SupplyPlanNotOpenError);
    }
  });

  it("closes open supply plans for a source document", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.update.mockReturnValueOnce([{ ...baseSupplyPlan, status: "CLOSED" }]);

    const result = await run(
      db,
      { target: "SOURCE_DOCUMENT", sourceType: "PURCHASE_ORDER", sourceId: "po-1" },
      ctx,
    );
    expect(result.ok).toBe(true);
    if (!result.ok) {
      throw result.error;
    }
    expect(result.value).toHaveProperty("supplyPlans");
    if ("supplyPlans" in result.value) {
      expect(result.value.supplyPlans).toHaveLength(1);
      expect(result.value.supplyPlans[0]?.status).toBe("CLOSED");
    }
    expect(spies.where).toHaveBeenCalledWith("sourceType", "=", "PURCHASE_ORDER");
    expect(spies.where).toHaveBeenCalledWith("sourceId", "=", "po-1");
    expect(spies.where).toHaveBeenCalledWith("status", "=", "OPEN");
  });

  it("closes open supply plans for selected source lines", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.update.mockReturnValueOnce([{ ...baseSupplyPlan, status: "CLOSED" }]);

    const result = await run(
      db,
      {
        target: "SOURCE_LINES",
        sourceType: "PURCHASE_ORDER",
        sourceLineIds: ["po-line-1"],
      },
      ctx,
    );

    expect(result.ok).toBe(true);
    if (!result.ok) {
      throw result.error;
    }
    expect(result.value).toHaveProperty("supplyPlans");
    expect(spies.where).toHaveBeenCalledWith("sourceLineId", "in", ["po-line-1"]);
  });

  it("returns no rows when sourceLineIds is empty", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(
      db,
      { target: "SOURCE_LINES", sourceType: "PURCHASE_ORDER", sourceLineIds: [] },
      ctx,
    );
    expect(result.ok).toBe(true);
    if (!result.ok) {
      throw result.error;
    }
    expect(result.value).toHaveProperty("supplyPlans");
    if ("supplyPlans" in result.value) {
      expect(result.value.supplyPlans).toEqual([]);
    }
  });
});
