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

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

  const validInput = {
    id: baseActiveWorkCenter.id,
    capacityAssumptions: 200,
    laborRate: 30.0,
  };

  it("updates an active work center without changing scope identity", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);
    spies.update.mockReturnValue({
      ...baseActiveWorkCenter,
      capacityAssumptions: 200,
      laborRate: 30.0,
    });

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

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.workCenter.capacityAssumptions).toBe(200);
      expect(result.value.workCenter.laborRate).toBe(30.0);
    }
    expect(spies.update).toHaveBeenCalled();
  });

  it("returns error when the work center does not exist", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined);

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

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

  it("looks up a work center by companyId, siteId, and code", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);
    spies.update.mockReturnValue({
      ...baseActiveWorkCenter,
      capacityAssumptions: 220,
    });

    const result = await run(
      db,
      {
        companyId: baseActiveWorkCenter.companyId,
        siteId: baseActiveWorkCenter.siteId,
        code: baseActiveWorkCenter.code,
        capacityAssumptions: 220,
      },
      ctx,
    );

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.workCenter.capacityAssumptions).toBe(220);
    }
  });

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

    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, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);

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

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

  it("preserves released cost baselines after update", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);
    spies.update.mockReturnValue({
      ...baseActiveWorkCenter,
      machineRate: 75.0,
    });

    const result = await run(db, { id: baseActiveWorkCenter.id, machineRate: 75.0 }, ctx);

    expect(result.ok).toBe(true);
    expect(spies.update).toHaveBeenCalledTimes(1);
    expect(spies.set).toHaveBeenCalledWith(expect.objectContaining({ machineRate: 75.0 }));
    expect(spies.set).toHaveBeenCalledWith(
      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
      expect.not.objectContaining({ companyId: expect.anything() }),
    );
  });

  it("returns error when the overhead method is not supported", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);

    const result = await run(
      db,
      { id: baseActiveWorkCenter.id, overheadAbsorptionMethod: "PER_ORDER" },
      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, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWorkCenter);

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

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