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

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,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();
  for (const line of input.lines) {
    await db
      .insertInto("SalesCreditNoteLine")
      .values({
        salesCreditNoteId: salesCreditNote!.id,
        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: salesCreditNote! });
}
