/* eslint-disable @typescript-eslint/no-unused-vars */
import type { Selectable, Transaction } from "../generated/kysely-tailordb";
import {
  EmptyScheduleError,
  ImmutableCompanyScopeError,
  InvalidInstallmentTotalError,
  InvalidScheduleLineError,
  PaymentTermNotFoundError,
} from "../lib/errors.generated";
import { validateScheduleLines } from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";

export type UpdatePurchasePaymentTermInput = {
  id: string;
  companyId?: string;
  name?: string;
  code?: string;
  scheduleLines?: Pick<
    Selectable<"PurchasePaymentTermLine">,
    "kind" | "days" | "fixedDayOfMonth" | "percentage" | "fixedAmount" | "note"
  >[];
  notes?: string | null;
};
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: UpdatePurchasePaymentTermInput & Partial<CF>,
  ctx: CommandContext,
) {
  const {
    id,
    companyId: inputCompanyId,
    name,
    code,
    scheduleLines: inputScheduleLines,
    notes,
    ...customFields
  } = input;
  const existing = await db
    .selectFrom("PurchasePaymentTerm")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();
  if (!existing) {
    return err(new PaymentTermNotFoundError(id));
  }

  if (inputCompanyId && inputCompanyId !== existing.companyId) {
    return err(new ImmutableCompanyScopeError(id));
  }

  let scheduleLines: Pick<
    Selectable<"PurchasePaymentTermLine">,
    "kind" | "days" | "fixedDayOfMonth" | "percentage" | "fixedAmount" | "note"
  >[];
  if (inputScheduleLines) {
    scheduleLines = inputScheduleLines;
  } else {
    const existingLines = await db
      .selectFrom("PurchasePaymentTermLine")
      .selectAll()
      .where("purchasePaymentTermId", "=", id)
      .execute();
    scheduleLines = existingLines;
  }

  const validation = validateScheduleLines(scheduleLines);
  if (validation === "EMPTY_SCHEDULE") {
    return err(new EmptyScheduleError(id));
  }
  if (validation === "INVALID_INSTALLMENT_TOTAL") {
    return err(new InvalidInstallmentTotalError(id));
  }
  if (validation === "INVALID_SCHEDULE_LINE") {
    return err(new InvalidScheduleLineError(id));
  }

  const paymentTerm = await db
    .updateTable("PurchasePaymentTerm")
    .set({
      ...(customFields as Record<string, unknown>),
      name: name ?? existing.name,
      code: code ?? existing.code,
      notes: notes === undefined ? existing.notes : notes,
      updatedAt: new Date(),
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirstOrThrow();

  if (inputScheduleLines) {
    await db
      .deleteFrom("PurchasePaymentTermLine")
      .where("purchasePaymentTermId", "=", id)
      .execute();

    const now = new Date();
    await db
      .insertInto("PurchasePaymentTermLine")
      .values(
        inputScheduleLines.map((line) => ({
          purchasePaymentTermId: id,
          kind: line.kind ?? "NET_DAYS",
          days: line.days ?? null,
          fixedDayOfMonth: line.fixedDayOfMonth ?? null,
          percentage: line.percentage ?? null,
          fixedAmount: line.fixedAmount ?? null,
          note: line.note ?? null,
          createdAt: now,
          updatedAt: null,
        })),
      )
      .execute();
  }

  return ok({ purchasePaymentTerm: paymentTerm });
}
