import { ok, type CommandContext, type QueryContext } from "@tailor-platform/erp-kit/core";
/* oxlint-disable typescript/no-explicit-any, typescript/no-unsafe-assignment, typescript/no-unsafe-return, typescript/require-await */
import { expect } from "vitest";

export const commandCtx: CommandContext = {
  actorId: "test-actor",
  permissions: ["purchase:*"],
};

export const queryCtx: QueryContext = {
  actorId: "test-actor",
  permissions: ["purchase:*"],
};

interface OkResult<T> {
  ok: true;
  value: T;
}

interface ErrResult {
  ok: false;
  error: unknown;
}

export function expectErr(
  result: OkResult<unknown> | ErrResult,
  errorClass: abstract new (...args: never[]) => Error,
) {
  expect(result.ok).toBe(false);
  if (!result.ok) {
    expect(result.error).toBeInstanceOf(errorClass);
  }
}

export function expectOk<T>(result: OkResult<T> | ErrResult) {
  expect(result.ok).toBe(true);
  if (!result.ok) {
    throw result.error;
  }
  return result.value;
}

export function mockBPQueries(
  overrides: { partner?: any; partnerRole?: any; identifications?: any[] } = {},
) {
  return {
    getPartner: async () => ok({ partner: overrides.partner ?? null }),
    getPartnerRole: async () => ok({ partnerRole: overrides.partnerRole ?? null }),
    listPartnerIdentificationsByPartner: async () =>
      ok({ items: overrides.identifications ?? [], hasNextPage: false }),
  };
}

export function mockItemQueries(overrides: { item?: any } = {}) {
  return {
    getItem: async () => ok({ item: overrides.item ?? null }),
  };
}

export function mockUnitQueries(overrides: { unit?: any } = {}) {
  return {
    getUnit: async () => ok({ unit: overrides.unit ?? null }),
  };
}

export function mockInventoryCommands() {
  const emptyEntries = () =>
    ok({
      inventoryLedgerEntries: [] as {
        id: string;
        sourceType: "CORRECTION" | "SCRAP" | "BLOCK" | "UNBLOCK" | "GOODS_RECEIPT" | "GOODS_ISSUE";
        sourceId: string;
        dcIndicator: "DR" | "CR";
        itemId: string;
        storageLocationId: string;
        quantity: string;
        amount: string | null;
        executedAt: Date;
        lotId: string | null;
        serialNumberId: string | null;
        createdAt: Date;
      }[],
    });
  return {
    receiveStock: async (_db: any, _input: any, _ctx: any) => emptyEntries(),
    receiveStockWithInspection: async (_db: any, _input: any, _ctx: any) => emptyEntries(),
  };
}
