import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';

/**
 * Reglas de tesorería — definen qué cuenta usar y con qué modo
 * cuando ocurren eventos automáticos (depositar cobro, pagar proveedor, etc.)
 *
 * tipo_operacion values:
 *   COBRO_DEPOSITADO    — cuenta donde se acreditan cheques de clientes depositados
 *   CHEQUE_DEBITADO     — cuenta desde donde se debitan cheques emitidos a proveedores
 *   PAGO_PROVEEDOR      — cuenta para pagos de facturas de proveedores
 *   COBRO_EFECTIVO      — cuenta de caja para cobros en efectivo
 *
 * modo:
 *   AUTOMATICO    — aplica sin pedir confirmación al usuario
 *   CONFIRMACION  — pre-rellena el selector pero el usuario debe confirmar
 *   MANUAL        — solo informativo, el usuario elige manualmente
 */
@Injectable()
export class TesReglasService {
  constructor(private readonly prisma: PrismaService) {}

  private readonly cuentaSelect = { select: { id: true, nombre: true, moneda: true, tipo: true } };
  private readonly medioSelect = { select: { id: true, descripcion: true } };

  async findAll(empresaId: string) {
    return this.prisma.tes_reglas.findMany({
      where: { empresa_id: empresaId },
      include: { cuenta: this.cuentaSelect, medio_pago: this.medioSelect },
      orderBy: [{ tipo_operacion: 'asc' }, { medio_pago_id: 'asc' }],
    });
  }

  /** Regla por tipo de operación y, opcionalmente, medio de pago (null = regla default). */
  async getRegla(empresaId: string, tipoOperacion: string, medioPagoId: string | null = null) {
    return this.prisma.tes_reglas.findFirst({
      where: { empresa_id: empresaId, tipo_operacion: tipoOperacion, medio_pago_id: medioPagoId },
      include: { cuenta: this.cuentaSelect, medio_pago: this.medioSelect },
    });
  }

  async upsert(
    empresaId: string,
    data: {
      tipo_operacion: string;
      medio_pago_id?: string | null;
      tipo_tesoreria?: string | null;
      cuenta_id?: string | null;
      modo?: string;
      activo?: boolean;
    },
  ) {
    const medioPagoId = data.medio_pago_id ?? null;
    const existente = await this.prisma.tes_reglas.findFirst({
      where: { empresa_id: empresaId, tipo_operacion: data.tipo_operacion, medio_pago_id: medioPagoId },
      select: { id: true },
    });
    if (existente) {
      return this.prisma.tes_reglas.update({
        where: { id: existente.id },
        data: {
          ...(data.cuenta_id !== undefined ? { cuenta_id: data.cuenta_id } : {}),
          ...(data.tipo_tesoreria !== undefined ? { tipo_tesoreria: data.tipo_tesoreria } : {}),
          ...(data.modo ? { modo: data.modo } : {}),
          ...(data.activo !== undefined ? { activo: data.activo } : {}),
          updated_at: new Date(),
        },
        include: { cuenta: this.cuentaSelect, medio_pago: this.medioSelect },
      });
    }
    return this.prisma.tes_reglas.create({
      data: {
        empresa_id: empresaId,
        tipo_operacion: data.tipo_operacion,
        medio_pago_id: medioPagoId,
        tipo_tesoreria: data.tipo_tesoreria ?? null,
        cuenta_id: data.cuenta_id ?? null,
        modo: data.modo ?? 'CONFIRMACION',
        activo: data.activo ?? true,
      },
      include: { cuenta: this.cuentaSelect, medio_pago: this.medioSelect },
    });
  }

  async remove(empresaId: string, id: string) {
    const regla = await this.prisma.tes_reglas.findFirst({ where: { id, empresa_id: empresaId } });
    if (!regla) throw new NotFoundException('Regla no encontrada');
    await this.prisma.tes_reglas.delete({ where: { id } });
    return { ok: true };
  }

  /** Devuelve el cuenta_id sugerido por la regla (default), o null si no hay regla activa */
  async getCuentaSugerida(empresaId: string, tipoOperacion: string): Promise<string | null> {
    const regla = await this.prisma.tes_reglas.findFirst({
      where: { empresa_id: empresaId, tipo_operacion: tipoOperacion, medio_pago_id: null },
      select: { cuenta_id: true, activo: true },
    });
    return regla?.activo && regla.cuenta_id ? regla.cuenta_id : null;
  }
}
