import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';

/** Correlativos internos del vertical. No son documentos fiscales. */
export type TipoNumeracionInm = 'OPI' | 'RES' | 'COT' | 'ADE' | 'CER' | 'INU' | 'DIS';

type ClientePrisma = PrismaService | Prisma.TransactionClient;

/**
 * OPI-0000001 (operación), RES-… (reserva), COT-… (cotización).
 *
 * Mismo mecanismo que NumeracionCrmService, con tabla propia (`inm_numeracion`)
 * para no acoplar el vertical al CRM, que se desarrolla en otra rama.
 * Pedilo siempre dentro de la transacción que crea la entidad: si la creación
 * falla, el número vuelve al pool en vez de dejar un hueco.
 */
@Injectable()
export class NumeracionInmService {
  constructor(private readonly prisma: PrismaService) {}

  async siguiente(empresa_id: string, tipo: TipoNumeracionInm, tx?: Prisma.TransactionClient): Promise<string> {
    const correr = async (c: ClientePrisma) => {
      await c.inm_numeracion.createMany({
        data: [{ empresa_id, tipo, prefijo: tipo }],
        skipDuplicates: true,
      });

      // FOR UPDATE: dos vendedores reservando a la vez no se llevan el mismo número.
      const filas = await c.$queryRaw<Array<{ id: string; prefijo: string; numero_actual: number; relleno: number }>>`
        SELECT id, prefijo, numero_actual, relleno
        FROM inm_numeracion
        WHERE empresa_id = ${empresa_id}::uuid AND tipo = ${tipo}
        FOR UPDATE`;

      const n = filas[0];
      const siguiente = n.numero_actual + 1;
      await c.inm_numeracion.update({
        where: { id: n.id },
        data: { numero_actual: siguiente, updated_at: new Date() },
      });
      return `${n.prefijo}-${String(siguiente).padStart(n.relleno, '0')}`;
    };

    return tx ? correr(tx) : this.prisma.$transaction((t) => correr(t));
  }
}
