import { UniqueID } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils";
import { literal, Transaction, WhereOptions } from "sequelize";
import {
  CustomerInvoiceNumber,
  CustomerInvoiceSerie,
  ICustomerInvoiceNumberGenerator,
} from "../../domain";
import { CustomerInvoiceModel } from "../sequelize";

/**
 * Generador de números de factura
 */
export class SequelizeInvoiceNumberGenerator implements ICustomerInvoiceNumberGenerator {
  public async nextForCompany(
    companyId: UniqueID,
    series: Maybe<CustomerInvoiceSerie>,
    transaction: Transaction
  ): Promise<Result<CustomerInvoiceNumber, Error>> {
    const where: WhereOptions = {
      company_id: companyId.toString(),
      is_proforma: false,
    };

    series.match(
      (serieVO) => {
        where.series = serieVO.toString();
      },
      () => {
        where.series = null;
      }
    );

    try {
      const lastInvoice = await CustomerInvoiceModel.findOne({
        attributes: ["invoice_number"],
        where,
        // Orden numérico real: CAST(... AS UNSIGNED)
        order: [literal("CAST(invoice_number AS UNSIGNED) DESC")],
        transaction,
        raw: true,
        // Bloqueo opcional para evitar carreras si estás dentro de una TX
        lock: transaction.LOCK.UPDATE, // requiere InnoDB y TX abierta
      });

      let nextValue = "00001"; // valor inicial por defecto

      if (lastInvoice) {
        const current = Number(lastInvoice.invoice_number);
        const next = Number.isFinite(current) && current > 0 ? current + 1 : 1;
        nextValue = String(next).padStart(5, "0");
      }

      const numberResult = CustomerInvoiceNumber.create(nextValue);
      if (numberResult.isFailure) {
        return Result.fail(numberResult.error);
      }

      return Result.ok(numberResult.data);
    } catch (error) {
      return Result.fail(
        new Error(
          `Error generating invoice number for company ${companyId}: ${(error as Error).message}`
        )
      );
    }
  }
}
