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

export type UpdateSalesPriceRuleInput = {
  salesPriceRuleId: string;
  salesPriceListId?: 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 | null;
};
export async function run(db: Transaction, input: UpdateSalesPriceRuleInput, ctx: CommandContext) {
  void ctx;
  const salesPriceRule = await db
    .selectFrom("SalesPriceRule")
    .selectAll()
    .where("id", "=", input.salesPriceRuleId)
    .forUpdate()
    .executeTakeFirst();
  if (!salesPriceRule) {
    return err(new SalespriceruleNotFoundError(input.salesPriceRuleId));
  }
  if (!["DRAFT", "ACTIVE"].includes(salesPriceRule.status)) {
    return err(new SalespriceruleNotEditableError(input.salesPriceRuleId));
  }
  const salesPriceListId = input.salesPriceListId ?? salesPriceRule.salesPriceListId;
  const salesPriceList = await db
    .selectFrom("SalesPriceList")
    .selectAll()
    .where("id", "=", salesPriceListId)
    .executeTakeFirst();
  if (!salesPriceList) {
    return err(new PriceListNotFoundError(salesPriceListId));
  }
  const unitPrice = input.unitPrice ?? salesPriceRule.unitPrice;
  const minimumQuantity = input.minimumQuantity ?? salesPriceRule.minimumQuantity;
  const effectiveFrom =
    input.effectiveFrom === undefined ? salesPriceRule.effectiveFrom : input.effectiveFrom;
  const effectiveTo =
    input.effectiveTo === undefined ? salesPriceRule.effectiveTo : input.effectiveTo;
  if (unitPrice <= 0 || minimumQuantity < 0) {
    return err(new InvalidUnitPriceError(input.salesPriceRuleId));
  }
  if (effectiveFrom && effectiveTo && effectiveTo < effectiveFrom) {
    return err(new InvalidEffectiveRangeError(input.salesPriceRuleId));
  }

  const updates: Updateable<"SalesPriceRule"> = {};
  if (input.salesPriceListId !== undefined) updates.salesPriceListId = input.salesPriceListId;
  if (input.customerId !== undefined) updates.customerId = input.customerId;
  if (input.channelId !== undefined) updates.channelId = input.channelId;
  if (input.currencyId !== undefined) updates.currencyId = input.currencyId;
  if (input.unitId !== undefined) updates.unitId = input.unitId;
  if (input.minimumQuantity !== undefined) updates.minimumQuantity = input.minimumQuantity;
  if (input.unitPrice !== undefined) updates.unitPrice = input.unitPrice;
  if (input.effectiveFrom !== undefined) updates.effectiveFrom = input.effectiveFrom;
  if (input.effectiveTo !== undefined) updates.effectiveTo = input.effectiveTo;
  if (input.priority !== undefined) updates.priority = input.priority;
  if (input.notes !== undefined) updates.notes = input.notes;

  if (Object.keys(updates).length === 0) {
    return ok({ salesPriceRule });
  }

  const updated = await db
    .updateTable("SalesPriceRule")
    .set(updates)
    .where("id", "=", input.salesPriceRuleId)
    .returningAll()
    .executeTakeFirstOrThrow();
  return ok({ salesPriceRule: updated });
}
