import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import { Transaction } from "../generated/kysely-tailordb";
import { DuplicateCodeError, MissingRequiredFieldError } from "../lib/errors.generated";
import { baseColorAttribute } from "../testing/fixtures";
import { run } from "./createProductAttribute";

describe("createProductAttribute", () => {
  it("returns error when code is empty", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(db, { code: "", name: "Color" });

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

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

    const result = await run(db, { code: "COLOR", name: "" });

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

  it("returns error when code already exists", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseColorAttribute); // getProductAttribute finds existing

    const result = await run(db, { code: "COLOR", name: "Color" });

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

  it("creates attribute successfully", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const createdAttribute = { ...baseColorAttribute, id: "new-attr-id" };

    spies.select.mockReturnValueOnce(undefined); // No existing attribute
    spies.insert.mockReturnValue(createdAttribute);

    const result = await run(db, { code: "COLOR", name: "Color" });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.productAttribute.code).toBe("COLOR");
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("passes custom fields through to insert", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const createdAttribute = { ...baseColorAttribute, id: "new-attr-id", priority: 5 };

    spies.select.mockReturnValueOnce(undefined); // No existing attribute
    spies.insert.mockReturnValue(createdAttribute);

    await run(db, { code: "COLOR", name: "Color", priority: 5 });

    expect(spies.values).toHaveBeenNthCalledWith(1, expect.objectContaining({ priority: 5 }));
  });
});
