import type { CommandContext } from "@tailor-platform/erp-kit/core";
import { describe, expect, it, vi } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  SiteNotFoundError,
  SiteInactiveError,
  DuplicateLocationNameError,
} from "../lib/errors.generated";
import type { OrganizationQueries } from "../module";
import { baseActiveSite, baseInactiveSite, baseStorageLocation } from "../testing/fixtures";
import { run } from "./createStorageLocation";

const ok = <T>(value: T) => ({ ok: true as const, value });

function mockOrgQueries(site: unknown): Pick<OrganizationQueries, "getSite"> {
  return {
    getSite: vi.fn().mockResolvedValue(ok({ site })),
  } as unknown as Pick<OrganizationQueries, "getSite">;
}

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

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

    const result = await run(
      db,
      { name: "Receiving Dock", code: "RCV-01", siteId: "nonexistent" },
      ctx,
      mockOrgQueries(null),
    );

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

  it("returns error when site inactive", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(
      db,
      { name: "Receiving Dock", code: "RCV-01", siteId: baseInactiveSite.id },
      ctx,
      mockOrgQueries(baseInactiveSite),
    );

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

  it("returns error when location name already exists in site", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseStorageLocation); // duplicate found

    const result = await run(
      db,
      { name: baseStorageLocation.name, code: "NEW", siteId: baseActiveSite.id },
      ctx,
      mockOrgQueries(baseActiveSite),
    );

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

  it("creates storage location", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const created = {
      ...baseStorageLocation,
      id: "new-loc-id",
      name: "Main Shelf",
      code: "MAIN",
    };

    spies.select.mockReturnValueOnce(undefined); // no duplicate
    spies.insert.mockReturnValue(created);

    const result = await run(
      db,
      { name: "Main Shelf", code: "MAIN", siteId: baseActiveSite.id },
      ctx,
      mockOrgQueries(baseActiveSite),
    );

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.storageLocation.name).toBe("Main Shelf");
      expect(result.value.storageLocation.siteId).toBe(baseActiveSite.id);
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("creates storage location without code", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const created = {
      ...baseStorageLocation,
      id: "new-loc-id",
      name: "Quarantine",
      code: null,
    };

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

    const result = await run(
      db,
      { name: "Quarantine", siteId: baseActiveSite.id },
      ctx,
      mockOrgQueries(baseActiveSite),
    );

    expect(result.ok).toBe(true);
    expect(spies.insert).toHaveBeenCalled();
  });

  it("creates storage location with storage condition", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const created = {
      ...baseStorageLocation,
      id: "new-loc-id",
      name: "Cold Area",
      code: "COLD",
      storageCondition: "cold",
    };

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

    const result = await run(
      db,
      {
        name: "Cold Area",
        code: "COLD",
        siteId: baseActiveSite.id,
        storageCondition: "cold",
      },
      ctx,
      mockOrgQueries(baseActiveSite),
    );

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.storageLocation.storageCondition).toBe("cold");
    }
  });
});
