import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import { Transaction } from "../generated/kysely-tailordb";
import {
  ValueNotFoundError,
  InvalidLabelError,
  DuplicateValueError,
} from "../lib/errors.generated";
import { baseColorRed, baseColorBlue } from "../testing/fixtures";
import { run } from "./updateProductAttributeValue";

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

    const result = await run(db, { id: "nonexistent", label: "Green" });

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

  it("returns error when label is empty", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseColorRed); // value found

    const result = await run(db, { id: baseColorRed.id, label: "" });

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

  it("returns error when label already exists on same attribute", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select
      .mockReturnValueOnce(baseColorRed) // value found
      .mockReturnValueOnce(baseColorBlue); // duplicate label exists

    const result = await run(db, { id: baseColorRed.id, label: "Blue" });

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

  it("returns error when label is whitespace only", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseColorRed); // value found

    const result = await run(db, { id: baseColorRed.id, label: "   " });

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

  it("updates label successfully", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const updatedValue = { ...baseColorRed, label: "Crimson" };

    spies.select
      .mockReturnValueOnce(baseColorRed) // value found
      .mockReturnValueOnce(undefined); // no duplicate
    spies.update.mockReturnValue(updatedValue);

    const result = await run(db, { id: baseColorRed.id, label: "Crimson" });

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.value.label).toBe("Crimson");
    }
    expect(spies.update).toHaveBeenCalled();
  });
});
