import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  IdentifierRequiredError,
  InvalidEffectiveRangeError,
  InvalidUnitPriceError,
  PriceListNotFoundError,
} from "../lib/errors.generated";

export interface CreateSalesPriceRuleInput {
  salesPriceListId: string;
  itemId: string;
  customerId?: string | null;
  channelId?: string | null;
  currencyId: string;
  unitId: string;
  minimumQuantity?: number;
  unitPrice: number;
  effectiveFrom?: Date | null;
  effectiveTo?: Date | null;
  priority?: number;
  notes?: string;
}

export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: CreateSalesPriceRuleInput & CF,
  ctx: CommandContext,
) {
  void ctx;
  const salesPriceList = await db
    .selectFrom("SalesPriceList")
    .selectAll()
    .where("id", "=", input.salesPriceListId)
    .executeTakeFirst();
  if (!salesPriceList) {
    return err(new PriceListNotFoundError(input.salesPriceListId));
  }
  if (!input.itemId || !input.currencyId || !input.unitId) {
    return err(new IdentifierRequiredError("sales-price-rule.scope"));
  }
  if (input.unitPrice <= 0 || (input.minimumQuantity ?? 0) < 0) {
    return err(new InvalidUnitPriceError(input.itemId));
  }
  if (input.effectiveFrom && input.effectiveTo && input.effectiveTo < input.effectiveFrom) {
    return err(new InvalidEffectiveRangeError(input.itemId));
  }
  const {
    salesPriceListId,
    itemId,
    customerId,
    channelId,
    currencyId,
    unitId,
    minimumQuantity,
    unitPrice,
    effectiveFrom,
    effectiveTo,
    priority,
    notes,
    ...customFields
  } = input;
  const salesPriceRule = await db
    .insertInto("SalesPriceRule")
    .values({
      ...(customFields as Record<string, unknown>),
      salesPriceListId,
      itemId,
      customerId: customerId ?? null,
      channelId: channelId ?? null,
      currencyId,
      unitId,
      minimumQuantity: minimumQuantity ?? 0,
      unitPrice,
      effectiveFrom: effectiveFrom ?? null,
      effectiveTo: effectiveTo ?? null,
      priority: priority ?? 0,
      status: "DRAFT",
      notes: notes ?? null,
    })
    .returningAll()
    .executeTakeFirstOrThrow();
  return ok({ salesPriceRule });
}
