import type { Transaction } from "../generated/kysely-tailordb";
import {
  CreditNoteNotEditableError,
  InvalidCreditNoteLineError,
  SalesCreditNoteNotFoundError,
} from "../lib/errors.generated";
import { type SalesCreditNoteLineInput } from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export type UpdateSalesCreditNoteInput = {
  salesCreditNoteId: string;
  reason?: string | null;
  lines?: SalesCreditNoteLineInput[];
};
export async function run(db: Transaction, input: UpdateSalesCreditNoteInput, ctx: CommandContext) {
  void ctx;
  const salesCreditNote = await db
    .selectFrom("SalesCreditNote")
    .selectAll()
    .where("id", "=", input.salesCreditNoteId)
    .forUpdate()
    .executeTakeFirst();
  if (!salesCreditNote) {
    return err(new SalesCreditNoteNotFoundError(input.salesCreditNoteId));
  }
  if (salesCreditNote.status !== "DRAFT") {
    return err(new CreditNoteNotEditableError(input.salesCreditNoteId));
  }
  if (input.lines) {
    for (const line of input.lines) {
      if (!line.salesInvoiceLineId) {
        return err(new InvalidCreditNoteLineError(input.salesCreditNoteId));
      }
    }
  }
  const updated = await db
    .updateTable("SalesCreditNote")
    .set({
      reason: input.reason === undefined ? salesCreditNote.reason : input.reason,
      updatedAt: new Date(),
    })
    .where("id", "=", input.salesCreditNoteId)
    .returningAll()
    .executeTakeFirst();
  if (input.lines) {
    await db
      .deleteFrom("SalesCreditNoteLine")
      .where("salesCreditNoteId", "=", input.salesCreditNoteId)
      .execute();
    for (const line of input.lines) {
      await db
        .insertInto("SalesCreditNoteLine")
        .values({
          salesCreditNoteId: input.salesCreditNoteId,
          salesInvoiceLineId: line.salesInvoiceLineId,
          quantity: line.quantity ?? null,
          amount: line.amount ?? null,
          reason: line.reason ?? null,
          taxAmount: line.taxAmount ?? null,
          createdAt: new Date(),
          updatedAt: null,
        })
        .executeTakeFirst();
    }
  }
  return ok({ salesCreditNote: updated! });
}
