import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  InvalidScopeError,
  DuplicateWorkCenterCodeError,
  InvalidCapacityError,
  InvalidRateError,
  InvalidOverheadMethodError,
  OverheadCurrencyRequiredError,
} from "../lib/errors.generated";
import { baseDraftWorkCenter } from "../testing/fixtures";
import { run } from "./createWorkCenter";
import type { CommandContext } from "@tailor-platform/erp-kit/module";

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

  const validInput = {
    code: "WC-NEW",
    companyId: "company-1",
    siteId: "site-1",
    capacityAssumptions: 100,
    laborRate: 25.0,
    machineRate: 50.0,
    calendarReference: "cal-standard",
  };

  it("creates a draft work center with positive capacity", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const createdWorkCenter = {
      ...baseDraftWorkCenter,
      id: "new-wc-id",
      code: "WC-NEW",
    };

    spies.select.mockReturnValueOnce(undefined);
    spies.insert.mockReturnValue(createdWorkCenter);

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

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.workCenter.status).toBe("DRAFT");
      expect(result.value.workCenter.code).toBe("WC-NEW");
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("returns error when scope is missing", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(db, { ...validInput, companyId: "" }, ctx);

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

  it("creates a draft work center without siteId when not required", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const createdWorkCenter = {
      ...baseDraftWorkCenter,
      id: "new-wc-id",
      code: "WC-NEW",
      siteId: null,
    };

    spies.select.mockReturnValueOnce(undefined);
    spies.insert.mockReturnValue(createdWorkCenter);

    const result = await run(db, { ...validInput, siteId: null }, ctx);

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.workCenter.status).toBe("DRAFT");
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("returns error when the code already exists in scope", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseDraftWorkCenter);

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

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

  it("returns error when capacity is not positive", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(db, { ...validInput, capacityAssumptions: 0 }, ctx);

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

  it("returns error when a rate is negative", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(db, { ...validInput, laborRate: -1 }, ctx);

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

  it("returns error when overhead method is invalid", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(db, { ...validInput, overheadAbsorptionMethod: "UNSUPPORTED" }, ctx);

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

  it("returns error when fixed-amount overhead omits currency", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(
      db,
      {
        ...validInput,
        overheadAbsorptionMethod: "FIXED_AMOUNT_PER_GOOD_UNIT",
        overheadAbsorptionCurrency: null,
      },
      ctx,
    );

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