import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { MonedasService } from 'src/monedas/monedas.service';
import { TesoreriaService } from 'src/tesoreria/tesoreria.service';
import { VendedoresCobradoresService } from 'src/vendedores-cobradores/vendedores-cobradores.service';
import { RendicionesService } from 'src/rendiciones/rendiciones.service';

/** Composición de datos del Home del cobrador. Solo reutiliza services existentes. */
@Injectable()
export class MobileDashboardService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly tesoreria: TesoreriaService,
    private readonly monedas: MonedasService,
    private readonly vendedores: VendedoresCobradoresService,
    private readonly rendiciones: RendicionesService,
  ) {}

  private async resolverSucursalUsuario(empresaId: string, usuarioId: string): Promise<string | null> {
    const asignacion = await this.prisma.asignacion_sucursal_caja_usuario.findFirst({
      where: { usuario_id: usuarioId, sucursal: { empresa_id: empresaId } },
      select: { sucursal_id: true },
    });
    if (asignacion?.sucursal_id) return asignacion.sucursal_id;
    const primera = await this.prisma.empresas_sucursales.findFirst({
      where: { empresa_id: empresaId, active: true },
      select: { id: true },
      orderBy: { created_at: 'asc' },
    });
    return primera?.id ?? null;
  }

  async get(empresaId: string, usuarioId: string) {
    const [cobrador, caja, empresaMonedas, sucursalId] = await Promise.all([
      this.vendedores.findCobradorVinculado(empresaId, usuarioId),
      // Solo la caja propia: ver MobileCajaService.actual().
      this.tesoreria.getSesionActiva(empresaId, undefined, usuarioId, { soloPropia: true }),
      this.monedas.findEmpresaMonedas(empresaId),
      this.resolverSucursalUsuario(empresaId, usuarioId),
    ]);

    // Cotización del día por cada moneda no principal (para cobros multimoneda).
    const cotizaciones = await Promise.all(
      empresaMonedas
        .filter((em) => !em.es_principal)
        .map(async (em) => {
          try {
            const cot = await this.monedas.getUltimaCotizacion(empresaId, em.moneda_id);
            return {
              moneda_id: em.moneda_id,
              codigo: cot.moneda?.codigo ?? em.moneda?.codigo ?? null,
              simbolo: cot.moneda?.simbolo ?? em.moneda?.simbolo ?? null,
              cotizacion_compra: cot.cotizacion_compra,
              cotizacion_venta: cot.cotizacion_venta,
              fecha: cot.fecha,
            };
          } catch {
            return null;
          }
        }),
    );

    const interesMoraActivo = await this.submoduloActivo(empresaId, 'ADM_INTERES_MORA');

    // Recibos EMITIDOS sin rendir de días anteriores. Se calcula acá para que
    // la app reciba la lista de una sola llamada y muestre el modal de aviso
    // al enfocarse en el Home (o al abrir la app al día siguiente).
    const rendicionPendienteDiasAnteriores = cobrador
      ? await this.rendiciones.getPendientesDiasAnterioresPorCobrador(empresaId, cobrador.id)
      : [];

    return {
      cobrador: cobrador
        ? { id: cobrador.id, nombre: `${cobrador.nombre} ${cobrador.apellido ?? ''}`.trim(), codigo: cobrador.codigo }
        : null,
      sin_cartera: !cobrador,
      sucursal_id: sucursalId,
      submodulos: { interes_mora: interesMoraActivo },
      caja: caja
        ? {
            sesion_id: (caja as { id: string }).id,
            estado: (caja as { estado: string }).estado,
            saldo_actual: (caja as { saldo_actual: number }).saldo_actual,
            fecha_apertura: (caja as { fecha_apertura: Date }).fecha_apertura,
            caja: (caja as { cajas?: unknown }).cajas ?? null,
          }
        : null,
      caja_abierta: !!caja,
      // Todas las monedas de la empresa (para el selector de moneda del cobro).
      monedas: empresaMonedas.map((em) => ({
        moneda_id: em.moneda_id,
        codigo: em.moneda?.codigo ?? null,
        simbolo: em.moneda?.simbolo ?? null,
        es_principal: !!em.es_principal,
      })),
      cotizaciones: cotizaciones.filter((c) => c !== null),
      rendicion_pendiente_dias_anteriores: rendicionPendienteDiasAnteriores,
    };
  }

  /**
   * ¿El submódulo está activo para la empresa? Replica la lógica de SubmoduloGuard
   * sin lanzar excepciones — devuelve un booleano para que la UI muestre/oculte
   * secciones (p.ej. el bloque de mora en el cobro).
   */
  private async submoduloActivo(empresaId: string, codigo: string): Promise<boolean> {
    const submodulo = await this.prisma.submodulos.findFirst({
      where: { codigo, active: true },
      select: { id: true, modulo_id: true, es_addon: true },
    });
    if (!submodulo) return false;

    const suscripcion = await this.prisma.suscripciones.findFirst({
      where: { empresa_id: empresaId, estado: { in: ['Activo', 'EnGracia'] } },
      orderBy: { created_at: 'desc' },
      select: { id: true },
    });
    if (!suscripcion) return false;

    if (submodulo.es_addon) {
      const addon = await this.prisma.suscripcion_submodulos.findFirst({
        where: { suscripcion_id: suscripcion.id, submodulo_id: submodulo.id, active: true },
        select: { id: true },
      });
      return !!addon;
    }

    const modulo = await this.prisma.suscripcion_modulos.findFirst({
      where: { suscripcion_id: suscripcion.id, modulo_id: submodulo.modulo_id, activo: true },
      select: { id: true },
    });
    return !!modulo;
  }
}
