import { Injectable } from '@nestjs/common';
import { envs } from 'src/config/envs';
import { ErpReadonlyService } from 'src/erp-readonly/erp-readonly.service';
import { FilaSesionUsuario, Sesion } from './sesion.types';

// Mismos estados que rechaza src/auth/jwt.strategy.ts del ERP (además de active=false).
const ESTADOS_NO_AUTORIZADOS = new Set(['Bloqueado', 'Inactivo', 'Eliminado']);

const TTL_MS = 60_000;
const MAX_ENTRADAS = 2_000;

/**
 * Relee la sesión del usuario en las vistas de soporte_ro, como hace el ERP en
 * cada request: estado del usuario, empresa efectiva, privilegios y alcance por
 * sucursal. Caché de 60 s por usuario.
 */
@Injectable()
export class SesionService {
  private readonly cache = new Map<string, { sesion: Sesion | null; vence: number }>();

  constructor(private readonly erp: ErpReadonlyService) {}

  async resolver(usuarioId: string): Promise<Sesion | null> {
    const ahora = Date.now();
    const enCache = this.cache.get(usuarioId);
    if (enCache && enCache.vence > ahora) return enCache.sesion;

    const sesion = await this.cargar(usuarioId);
    if (this.cache.size >= MAX_ENTRADAS) this.cache.clear();
    this.cache.set(usuarioId, { sesion, vence: ahora + TTL_MS });
    return sesion;
  }

  private async cargar(usuarioId: string): Promise<Sesion | null> {
    // Solo app.usuario_id: las vistas de sesión derivan la empresa de la fila del usuario.
    return this.erp.runScoped({ usuarioId }, async (consulta) => {
      const [u] = await consulta<FilaSesionUsuario>(`SELECT * FROM soporte_ro.v_sesion_usuario`);
      if (!u || u.active === false || (u.estado && ESTADOS_NO_AUTORIZADOS.has(u.estado))) {
        return null;
      }

      const privilegios = await consulta<{ codigo: string }>(`SELECT codigo FROM soporte_ro.v_privilegios_usuario`);
      const accesoElevado = u.is_superadmin || u.empresa_tipo === 'holding' || u.empresa_tipo === 'reseller';

      let alcance: Sesion['alcance'] = null;
      if (!accesoElevado) {
        const filas = await consulta<{ sucursal_id: string; establecimiento: string | null }>(
          `SELECT sucursal_id, establecimiento FROM soporte_ro.v_alcance_usuario`,
        );
        // Sin asignaciones = sin restricción, igual que el ERP.
        if (filas.length > 0) {
          alcance = {
            sucursalIds: filas.map((f) => f.sucursal_id),
            establecimientos: filas.map((f) => f.establecimiento).filter((e): e is string => !!e),
          };
        }
      }

      return {
        usuarioId: u.id,
        username: u.username ?? '',
        nombre: [u.nombres, u.apellidos].filter(Boolean).join(' ') || (u.username ?? ''),
        empresaId: u.empresa_id,
        empresaRuc: u.empresa_ruc,
        empresaRazonSocial: u.empresa_razon_social,
        empresaTipo: u.empresa_tipo,
        isSuperadmin: u.is_superadmin,
        accesoElevado,
        privilegios: new Set(privilegios.map((p) => p.codigo)),
        alcance,
        esNovasis: u.is_superadmin && u.empresa_id_original === envs.holdingEmpresaId,
      };
    });
  }
}
