/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import type { Transaction } from "../generated/kysely-tailordb";
import {
  DuplicateSupplierInvoiceNumberError,
  EmptyBillLinesError,
  InvalidBilledQuantityError,
  PaymentTermSnapshotMissingError,
  PurchaseOrderCancelledError,
  PurchaseOrderLineNotFoundError,
  SupplierNotFoundError,
  SupplierTaxIdentificationMissingError,
} from "../lib/errors.generated";
import {
  encodeJson,
  findOrderLine,
  findPurchaseBillDuplicate,
  getDefaultPartnerIdentification,
  normalizeBillLines,
  type PurchaseBillLineInput,
} from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface CreatePurchaseBillInput {
  companyId: string;
  supplierId: string;
  invoiceNumber: string;
  invoiceDate: Date;
  lines: PurchaseBillLineInput[];
  supplierTaxIdentification?: string;
}

export async function run(db: Transaction, input: CreatePurchaseBillInput, ctx: CommandContext) {
  void ctx;
  const supplier = await db
    .selectFrom("BusinessPartner")
    .selectAll()
    .where("id", "=", input.supplierId)
    .executeTakeFirst();
  if (!supplier) {
    return err(new SupplierNotFoundError(input.supplierId));
  }
  if (await findPurchaseBillDuplicate(db, input.companyId, input.supplierId, input.invoiceNumber)) {
    return err(new DuplicateSupplierInvoiceNumberError(input.invoiceNumber));
  }
  if (input.lines.length === 0) {
    return err(new EmptyBillLinesError(input.invoiceNumber));
  }

  const purchaseOrders = await db.selectFrom("PurchaseOrder").selectAll().execute();
  const normalizedLines: ReturnType<typeof normalizeBillLines> = [];
  for (const line of normalizeBillLines(input.lines)) {
    const match = findOrderLine(purchaseOrders, line.purchaseOrderLineId);
    if (!match) {
      return err(new PurchaseOrderLineNotFoundError(line.purchaseOrderLineId));
    }
    if (line.quantity <= 0) {
      return err(new InvalidBilledQuantityError(line.purchaseOrderLineId));
    }
    if (match.order.status === "CANCELLED") {
      return err(new PurchaseOrderCancelledError(String(match.order.id)));
    }
    normalizedLines.push({
      ...line,
      billedUnitPrice: line.billedUnitPrice ?? match.line.unitPrice,
    });
  }

  const firstMatch = normalizedLines[0]
    ? findOrderLine(purchaseOrders, normalizedLines[0].purchaseOrderLineId)
    : null;
  if (!firstMatch?.order.paymentTermSnapshot) {
    return err(new PaymentTermSnapshotMissingError(input.invoiceNumber));
  }

  const supplierTaxIdentification =
    input.supplierTaxIdentification ??
    ((await getDefaultPartnerIdentification(db, input.supplierId))?.value as string | undefined);
  if (!supplierTaxIdentification) {
    return err(new SupplierTaxIdentificationMissingError(input.supplierId));
  }

  const purchaseBill = await db
    .insertInto("PurchaseBill")
    .values({
      companyId: input.companyId,
      supplierId: input.supplierId,
      invoiceNumber: input.invoiceNumber,
      invoiceDate: input.invoiceDate,
      status: "DRAFT",
      lines: encodeJson(normalizedLines),
      paymentTermSnapshot: firstMatch.order.paymentTermSnapshot as string,
      supplierTaxIdentification,
      matchingMode: null,
      varianceReason: null,
      releaseReason: null,
      dueSchedule: null,
      downstreamAccepted: false,
      comparisonEvidence: null,
      billReadyHandoff: null,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();

  return ok({ purchaseBill: purchaseBill! });
}
