import { Body, Controller, Delete, Get, Param, Post, Query, Res, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import type { Response } from 'express';
import { RequireModule } from '../../auth/decorators/require-module.decorator';
import { RequirePermission } from '../../auth/decorators/require-permission.decorator';
import type { LoginUserInfo } from '../../auth/dto/login.dto';
import { GetUser } from '../../auth/get-user.decorator';
import { ModuleGuard } from '../../auth/guards/module.guard';
import { PermissionGuard } from '../../auth/guards/permission.guard';
import {
  AccionLiquidacionDto,
  AgregarLineaManualDto,
  CreateLiquidacionDto,
  QueryPlanillaLiquidacionDto,
  QueryLiquidacionesDto,
} from '../dto/liquidaciones.dto';
import { LiquidacionesService } from '../services/liquidaciones.service';

@ApiTags('RRHH - Liquidaciones')
@Controller({ path: 'rrhh/liquidaciones', version: '1' })
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('RRHH')
@ApiBearerAuth()
export class LiquidacionesController {
  constructor(private readonly service: LiquidacionesService) {}

  @Get()
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({ summary: 'Listar liquidaciones' })
  listar(@GetUser() user: LoginUserInfo, @Query() query: QueryLiquidacionesDto) {
    return this.service.listar(user.empresa_id, query);
  }

  @Get(':id')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({ summary: 'Obtener liquidación con resumen por empleado' })
  obtener(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.obtener(id, user.empresa_id);
  }

  @Get(':id/empleados/:empleadoId')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({ summary: 'Detalle conceptual de un empleado en la liquidación' })
  detalleEmpleado(
    @Param('id') id: string,
    @Param('empleadoId') empleadoId: string,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.obtenerDetalleEmpleado(id, empleadoId, user.empresa_id);
  }

  @Get(':id/asiento-contable')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({ summary: 'Asiento contable generado por la liquidación (si existe)' })
  obtenerAsiento(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.obtenerAsientoContable(id, user.empresa_id);
  }

  @Get(':id/planilla-control')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({
    summary: 'Planilla de control (pivot empleado × concepto) en JSON o XLSX',
    description:
      'Disponible en PRE_LIQUIDACION y CERRADA. Una fila por empleado, columnas por concepto, ' +
      'totales por columna y por fila. Útil para revisión gerencial / firma previa al cierre.',
  })
  async planillaControl(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Query() query: QueryPlanillaLiquidacionDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    if (query.format === 'xlsx') {
      const { buffer, filename } = await this.service.generarPlanillaControlXlsx(
        id,
        user.empresa_id,
      );
      res.setHeader(
        'Content-Type',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      );
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      res.send(buffer);
      return;
    }
    return this.service.obtenerPlanillaControl(id, user.empresa_id);
  }

  @Get(':id/planilla')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_VER')
  @ApiOperation({
    summary: 'Planilla consolidada de liquidación mensual cerrada (json/xlsx)',
    description:
      'Solo disponible para liquidaciones tipo MENSUAL y estado CERRADA. ' +
      'format=json retorna dataset consolidado; format=xlsx retorna archivo descargable.',
  })
  async planilla(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Query() query: QueryPlanillaLiquidacionDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    if (query.format === 'xlsx') {
      const { buffer, filename } = await this.service.generarPlanillaConsolidadaXlsx(
        id,
        user.empresa_id,
      );
      res.setHeader(
        'Content-Type',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      );
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      res.send(buffer);
      return;
    }

    return this.service.obtenerPlanillaConsolidada(id, user.empresa_id);
  }

  @Post(':id/integrar-contabilidad')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_PAGAR')
  @ApiOperation({
    summary: 'Reintentar la integración contable de una liquidación CERRADA',
    description:
      'Útil cuando la liquidación se cerró sin que estuviera disponible el módulo Contabilidad ' +
      'o faltaban mapeos de cuentas. Es idempotente: si ya existe asiento no lo duplica.',
  })
  integrarContabilidad(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.reintegrarContabilidad(id, user.empresa_id);
  }

  @Post()
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_CREAR')
  @ApiOperation({ summary: 'Crear liquidación mensual (estado BORRADOR)' })
  crear(@GetUser() user: LoginUserInfo, @Body() dto: CreateLiquidacionDto) {
    return this.service.crear(user.empresa_id, dto, user.id);
  }

  @Post(':id/calcular')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_CREAR')
  @ApiOperation({
    summary: 'Ejecutar el motor de cálculo (→ PRE_LIQUIDACION)',
    description:
      'Genera detalle y resumen por empleado: salario proporcional, IPS (obrero/patronal/admin con regla SMLV/microempresa), ' +
      'anticipos aprobados del período, cuotas de préstamo pendientes, novedades no justificadas y planillas externas importadas. ' +
      'Idempotente: recalcular reemplaza líneas automáticas/importadas y conserva líneas manuales.',
  })
  calcular(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.calcular(id, user.empresa_id);
  }

  @Post(':id/lineas-manuales')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_CREAR')
  @ApiOperation({ summary: 'Agregar ajuste manual (horas extra, bono, comisión, descuento) a un empleado' })
  agregarLineaManual(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: AgregarLineaManualDto,
  ) {
    return this.service.agregarLineaManual(id, user.empresa_id, dto);
  }

  @Delete(':id/lineas/:lineaId')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_CREAR')
  @ApiOperation({ summary: 'Quitar un ajuste manual' })
  eliminarLineaManual(
    @Param('id') id: string,
    @Param('lineaId') lineaId: string,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.eliminarLineaManual(id, lineaId, user.empresa_id);
  }

  @Post(':id/cerrar')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_APROBAR')
  @ApiOperation({
    summary: 'Cerrar liquidación (→ CERRADA, inmutable)',
    description:
      'Valida que no haya quincenal pendiente del período ni netos negativos (salvo excepción formal parametrizada y auditada). Marca anticipos como DESCONTADO, ' +
      'cuotas de préstamo como DESCONTADO (actualiza saldos), planillas externas como APLICADA y novedades consumidas.',
  })
  cerrar(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: AccionLiquidacionDto,
  ) {
    return this.service.cerrar(id, user.empresa_id, dto, user.id);
  }

  @Post(':id/anular')
  @RequirePermission('RRHH', 'RH_LIQ_LIQUIDACION_ANULAR')
  @ApiOperation({ summary: 'Anular liquidación (solo BORRADOR o PRE_LIQUIDACION)' })
  anular(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: AccionLiquidacionDto,
  ) {
    return this.service.anular(id, user.empresa_id, dto, user.id);
  }
}
