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

export interface CreateSalesCreditNoteInput {
  salesInvoiceId: string;
  creditDate?: Date;
  reason?: string;
  lines: SalesCreditNoteLineInput[];
}

export async function run(db: Transaction, input: CreateSalesCreditNoteInput, ctx: CommandContext) {
  void ctx;
  const salesInvoice = await db
    .selectFrom("SalesInvoice")
    .selectAll()
    .where("id", "=", input.salesInvoiceId)
    .executeTakeFirst();
  if (!salesInvoice) {
    return err(new SalesInvoiceNotFoundError(input.salesInvoiceId));
  }
  if (salesInvoice.status !== "ISSUED") {
    return err(new InvoiceNotIssuedError(input.salesInvoiceId));
  }
  if (!input.lines.length) {
    return err(new InvalidCreditNoteLineError(input.salesInvoiceId));
  }
  for (const line of input.lines) {
    const invoiceLine = await db
      .selectFrom("SalesInvoiceLine")
      .selectAll()
      .where("id", "=", line.salesInvoiceLineId)
      .executeTakeFirst();
    if (invoiceLine?.salesInvoiceId !== input.salesInvoiceId) {
      return err(new InvalidCreditNoteLineError(line.salesInvoiceLineId));
    }
  }
  const salesCreditNote = await db
    .insertInto("SalesCreditNote")
    .values({
      companyId: salesInvoice.companyId,
      customerId: salesInvoice.customerId,
      salesInvoiceId: input.salesInvoiceId,
      status: "DRAFT",
      creditNoteNumber: null,
      creditDate: input.creditDate ?? new Date(),
      reason: input.reason ?? null,
      correctionSnapshot: null,
    })
    .returningAll()
    .executeTakeFirstOrThrow();
  if (input.lines.length > 0) {
    await db
      .insertInto("SalesCreditNoteLine")
      .values(
        input.lines.map((line) => ({
          salesCreditNoteId: salesCreditNote.id,
          salesInvoiceLineId: line.salesInvoiceLineId,
          quantity: line.quantity ?? null,
          amount: line.amount ?? null,
          reason: line.reason ?? null,
          taxAmount: line.taxAmount ?? null,
        })),
      )
      .execute();
  }
  return ok({ salesCreditNote });
}
