import {
  Controller,
  Get,
  Param,
  Patch,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { GetUser } from 'src/auth/get-user.decorator';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { RequireSubmodulo } from 'src/auth/decorators';
import { SubmoduloGuard } from 'src/auth/guards';
import { AlertsService } from './alerts/alerts.service';
import { InsightsService } from './insights/insights.service';
import { TimelineService } from './timeline/timeline.service';
import { RecalculoService } from './recalculo/recalculo.service';
import { PredictionsService } from './predictions/predictions.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { RrhhContextService } from './shared/rrhh-context.service';
import { ModulesContextService } from './shared/modules-context.service';
import { filtrarMetricasPorDominios, filtrarPorDominios } from './shared/domain-filters';

@ApiTags('ai-dashboard')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), SubmoduloGuard)
@RequireSubmodulo('REP_DASHBOARD_IA')
@Controller({ path: 'ai-dashboard', version: '1' })
export class AiDashboardController {
  constructor(
    private readonly insightsService: InsightsService,
    private readonly alertsService: AlertsService,
    private readonly timelineService: TimelineService,
    private readonly recalculoService: RecalculoService,
    private readonly predictionsService: PredictionsService,
    private readonly prisma: PrismaService,
    private readonly rrhhContext: RrhhContextService,
    private readonly modulesContext: ModulesContextService,
  ) {}

  @Get('active-domains')
  @ApiOperation({ summary: 'Dominios AI activos para la empresa (según módulos suscriptos)' })
  async getActiveDomains(@GetUser() user: LoginUserInfo) {
    const dominios = await this.modulesContext.getActiveDomains(user.empresa_id);
    return { dominios };
  }

  @Get('resumen')
  @ApiOperation({ summary: 'Obtener insight vigente tipo resumen_ejecutivo' })
  async getResumen(@GetUser() user: LoginUserInfo) {
    const insight = await this.prisma.ai_insights.findFirst({
      where: {
        empresa_id: user.empresa_id,
        tipo: 'resumen_ejecutivo',
        vigente: true,
      },
      orderBy: { generado_at: 'desc' },
    });
    return insight ?? { mensaje: 'Sin resumen disponible. Use POST /ai-config/recalcular para generarlo.' };
  }

  @Get('alertas')
  @ApiOperation({ summary: 'Obtener alertas no leídas y no resueltas' })
  async getAlertas(@GetUser() user: LoginUserInfo) {
    const alertas = await this.prisma.ai_alertas.findMany({
      where: {
        empresa_id: user.empresa_id,
        leida: false,
        resuelta: false,
      },
      orderBy: [{ criticidad: 'asc' }, { created_at: 'desc' }],
    });
    const dominios = await this.modulesContext.getActiveDomains(user.empresa_id);
    const porDominio = filtrarPorDominios(alertas, dominios);
    // Si el usuario no puede ver RRHH (permiso, no módulo), ocultar alertas rrhh_*
    const puedeRrhh = await this.rrhhContext.puedeVerRRHH(user.id, user.empresa_id);
    return puedeRrhh ? porDominio : porDominio.filter((a) => !a.tipo?.startsWith('rrhh_'));
  }

  @Patch('alertas/:id/leer')
  @ApiOperation({ summary: 'Marcar alerta como leída' })
  marcarLeida(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.prisma.ai_alertas.updateMany({
      where: { id, empresa_id: user.empresa_id },
      data: { leida: true },
    });
  }

  @Patch('alertas/:id/resolver')
  @ApiOperation({ summary: 'Marcar alerta como resuelta' })
  marcarResuelta(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.prisma.ai_alertas.updateMany({
      where: { id, empresa_id: user.empresa_id },
      data: { resuelta: true, leida: true },
    });
  }

  @Get('timeline')
  @ApiOperation({ summary: 'Obtener eventos del timeline (últimos 7 días), ordenados por relevancia' })
  @ApiQuery({ name: 'dias', required: false, description: 'Cantidad de días hacia atrás (default: 7)' })
  async getTimeline(
    @GetUser() user: LoginUserInfo,
    @Query('dias') dias?: string,
  ) {
    const cantDias = dias ? parseInt(dias, 10) : 7;
    const [eventos, dominios] = await Promise.all([
      this.timelineService.getEventosRecientes(user.empresa_id, cantDias, user.id),
      this.modulesContext.getActiveDomains(user.empresa_id),
    ]);
    return filtrarPorDominios(eventos as any[], dominios);
  }

  @Get('predicciones')
  @ApiOperation({ summary: 'Obtener todas las predicciones: cobranza, riesgo clientes, ventas, nómina' })
  async getPredicciones(@GetUser() user: LoginUserInfo) {
    const [preds, dominios] = await Promise.all([
      this.predictionsService.todasLasPredicciones(user.empresa_id, user.id),
      this.modulesContext.getActiveDomains(user.empresa_id),
    ]);
    const has = (d: any) => dominios.includes(d);
    return {
      cobranza: has('COBRANZAS') ? preds.cobranza : null,
      clientesEnRiesgo: has('COBRANZAS') || has('CLIENTES') ? preds.clientesEnRiesgo : null,
      ventas: has('VENTAS') ? preds.ventas : null,
      compras: has('COMPRAS') ? preds.compras : null,
      reorden: has('INVENTARIO') ? preds.reorden : null,
      flujoCaja: has('TESORERIA') ? preds.flujoCaja : null,
      nominaRRHH: has('RRHH') ? preds.nominaRRHH : null,
      empleadosRiesgo: has('RRHH') ? preds.empleadosRiesgo : null,
    };
  }

  @Get('predicciones/nomina')
  @ApiOperation({ summary: 'Proyección de nómina próximo mes (solo si módulo RRHH + permiso). Retorna null si no aplica.' })
  getProyeccionNomina(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.proyeccionNominaRRHH(user.empresa_id, user.id);
  }

  @Get('predicciones/rrhh-riesgo-desvinculacion')
  @ApiOperation({ summary: 'Empleados con patrón de faltas + anticipos (riesgo desvinculación). Retorna null si no aplica.' })
  getRiesgoDesvinculacion(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.empleadosRiesgoDesvinculacion(user.empresa_id, user.id);
  }

  @Get('predicciones/cobranza')
  @ApiOperation({ summary: 'Proyección de cobranza próximos 30 días por cobrador' })
  getProyeccionCobranza(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.proyeccionCobranza(user.empresa_id);
  }

  @Get('predicciones/riesgo')
  @ApiOperation({ summary: 'Clientes en riesgo de mora ordenados por score' })
  getClientesRiesgo(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.clientesEnRiesgo(user.empresa_id);
  }

  @Get('predicciones/ventas')
  @ApiOperation({ summary: 'Proyección de ventas próximo mes con tendencia' })
  getProyeccionVentas(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.proyeccionVentas(user.empresa_id);
  }

  @Get('predicciones/compras')
  @ApiOperation({ summary: 'Proyección de compras próximo mes con tendencia' })
  getProyeccionCompras(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.proyeccionCompras(user.empresa_id);
  }

  @Get('predicciones/reorden')
  @ApiOperation({ summary: 'Productos que necesitan reorden por stock bajo vs velocidad de ventas' })
  getProductosReorden(@GetUser() user: LoginUserInfo) {
    return this.predictionsService.productosParaReordenar(user.empresa_id);
  }

  @Post('recalcular')
  @ApiOperation({ summary: 'Forzar recálculo manual de insights, alertas y timeline' })
  recalcular(@GetUser() user: LoginUserInfo) {
    return this.recalculoService.ejecutar(user.empresa_id);
  }

  @Get('metricas')
  @ApiOperation({ summary: 'Datos crudos del período para KpiCards (sin LLM)' })
  @ApiQuery({ name: 'periodo', required: false, description: 'Período YYYY-MM (default: mes actual)' })
  async getMetricas(
    @GetUser() user: LoginUserInfo,
    @Query('periodo') periodo?: string,
  ) {
    const hoy = new Date();
    const p = periodo ?? `${hoy.getFullYear()}-${String(hoy.getMonth() + 1).padStart(2, '0')}`;
    const [metricas, dominios] = await Promise.all([
      this.insightsService.calcularMetricasPeriodo(user.empresa_id, p),
      this.modulesContext.getActiveDomains(user.empresa_id),
    ]);
    return filtrarMetricasPorDominios(metricas, dominios);
  }

  @Get('metricas/rrhh')
  @ApiOperation({
    summary: 'KPIs de RRHH del período (solo si la empresa tiene el módulo y el usuario tiene permiso). Retorna null si no aplica.',
  })
  @ApiQuery({ name: 'periodo', required: false, description: 'Período YYYY-MM (default: mes actual)' })
  getMetricasRRHH(
    @GetUser() user: LoginUserInfo,
    @Query('periodo') periodo?: string,
  ) {
    return this.insightsService.calcularMetricasRRHH(user.empresa_id, user.id, periodo);
  }
}
