import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  Res,
  UseGuards,
  ValidationPipe,
} from '@nestjs/common';
import { Response } from 'express';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { RequireModule, RequirePermission } from 'src/auth/decorators';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { GetUser } from 'src/auth/get-user.decorator';
import { ModuleGuard } from 'src/auth/guards/module.guard';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { CerrarRendicionDto } from './dto/cerrar-rendicion.dto';
import { CreateAdelantoAdicionalDto } from './dto/create-adelanto.dto';
import { CreateGastoRendicionDto } from './dto/create-gasto-rendicion.dto';
import { CreateRendicionViaticoDto } from './dto/create-rendicion-viatico.dto';
import { ListarRendicionesDto } from './dto/listar-rendiciones.dto';
import { UpdateRendicionViaticoDto } from './dto/update-rendicion-viatico.dto';
import { RendicionViaticosService } from './rendicion-viaticos.service';

@ApiTags('Rendición de Viáticos')
@Controller({ path: 'rendicion-viaticos', version: '1' })
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('RRHH')
@ApiBearerAuth()
export class RendicionViaticosController {
  constructor(private readonly service: RendicionViaticosService) {}

  // ── Config ───────────────────────────────────────────────────────────────

  @Get('config')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Obtener configuración de viáticos por empresa' })
  getConfig(@GetUser() user: LoginUserInfo) {
    return this.service.getConfig(user.empresa_id);
  }

  @Patch('config')
  @RequirePermission('RRHH', 'RH_VIA_CONFIG_EDITAR')
  @ApiOperation({ summary: 'Actualizar configuración de viáticos por empresa' })
  updateConfig(
    @GetUser() user: LoginUserInfo,
    @Body(ValidationPipe) dto: {
      anticipo_viatico_requiere_aprobacion?: boolean;
      anticipo_viatico_umbral_aprobacion?: number;
      reintegro_viatico_default?: 'INMEDIATO' | 'DIFERIDO';
      viatico_dias_alerta?: number;
    },
  ) {
    return this.service.updateConfig(user.empresa_id, dto, user.id);
  }

  // ── Reportes (Fase 4) ────────────────────────────────────────────────────

  @Get('reporte-saldos-empleado')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Reporte de saldos abiertos por empleado' })
  reporteSaldosPorEmpleado(
    @GetUser() user: LoginUserInfo,
    @Query('empleado_id') empleadoId?: string,
    @Query('solo_con_saldo') soloConSaldo?: string,
  ) {
    return this.service.reporteSaldosPorEmpleado(user.empresa_id, {
      empleado_id: empleadoId,
      solo_con_saldo: soloConSaldo === 'true' || soloConSaldo === '1',
    });
  }

  @Get('reporte-saldos-empleado/pdf')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'PDF del reporte de saldos abiertos por empleado' })
  async reporteSaldosPorEmpleadoPDF(
    @GetUser() user: LoginUserInfo,
    @Res() res: Response,
    @Query('empleado_id') empleadoId?: string,
    @Query('solo_con_saldo') soloConSaldo?: string,
  ) {
    const { pdfBuffer, filename } = await this.service.generarPDFReporteSaldos(user.empresa_id, {
      empleado_id: empleadoId,
      solo_con_saldo: soloConSaldo === 'true' || soloConSaldo === '1',
    });
    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${filename}"`,
      'Content-Length': String(pdfBuffer.length),
    });
    res.end(pdfBuffer);
  }

  // ── CxP a empleados (Fase 4) ─────────────────────────────────────────────

  @Get('cxp-empleados')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Listar cuentas por pagar a empleados (reintegros diferidos)' })
  listarCxpEmpleados(
    @GetUser() user: LoginUserInfo,
    @Query('empleado_id') empleadoId?: string,
    @Query('estado') estado?: string,
    @Query('desde') desde?: string,
    @Query('hasta') hasta?: string,
  ) {
    return this.service.listarCxpEmpleados(user.empresa_id, {
      empleado_id: empleadoId,
      estado,
      desde,
      hasta,
    });
  }

  @Get('cxp-empleados/:cxpId/pdf')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Comprobante PDF del pago de una CxP a empleado' })
  async pdfCxpEmpleado(
    @GetUser() user: LoginUserInfo,
    @Param('cxpId') cxpId: string,
    @Res() res: Response,
  ) {
    const { pdfBuffer, filename } = await this.service.generarPDFPagoCxp(user.empresa_id, cxpId);
    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${filename}"`,
      'Content-Length': String(pdfBuffer.length),
    });
    res.end(pdfBuffer);
  }

  @Post('cxp-empleados/:cxpId/pagar')
  @RequirePermission('RRHH', 'RH_VIA_CXP_PAGAR')
  @ApiOperation({ summary: 'Registrar pago (total o parcial) de una CxP a empleado' })
  pagarCxpEmpleado(
    @GetUser() user: LoginUserInfo,
    @Param('cxpId') cxpId: string,
    @Body(ValidationPipe) dto: {
      monto: number;
      fecha: string;
      medio_pago_id?: string;
      tes_cuenta_id: string;
      numero_operacion?: string;
      observaciones?: string;
      numero_cheque?: string;
      banco_emisor?: string;
      titular_cheque?: string;
      fecha_emision_cheque?: string;
      fecha_vencimiento_cheque?: string;
    },
  ) {
    return this.service.pagarCxpEmpleado(user.empresa_id, cxpId, dto, user.id);
  }

  // ── Rendiciones ──────────────────────────────────────────────────────────

  @Post()
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_CREAR')
  @ApiOperation({ summary: 'Crear rendición (opcionalmente con primer adelanto)' })
  async create(
    @GetUser() user: LoginUserInfo,
    @Body(ValidationPipe) dto: CreateRendicionViaticoDto,
  ) {
    const result = await this.service.create(user.empresa_id, dto, user.id);
    // Ejecutar impacto contable + tesorería post-commit
    await this.service.ejecutarImpactosPendientes(user.empresa_id, result.id, user.id);
    return this.service.findOne(user.empresa_id, result.id);
  }

  @Get()
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Listar rendiciones (paginado con filtros)' })
  findAll(@GetUser() user: LoginUserInfo, @Query() filtros: ListarRendicionesDto) {
    return this.service.findAll(user.empresa_id, filtros);
  }

  @Get(':id')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Detalle de rendición' })
  findOne(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.service.findOne(user.empresa_id, id);
  }

  @Get(':id/pdf')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_VER')
  @ApiOperation({ summary: 'Comprobante PDF de la rendición (msv-kude)' })
  async pdf(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Res() res: Response,
  ) {
    const { pdfBuffer, filename } = await this.service.generarPDF(user.empresa_id, id);
    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${filename}"`,
      'Content-Length': String(pdfBuffer.length),
    });
    res.end(pdfBuffer);
  }

  @Patch(':id')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_CREAR')
  @ApiOperation({ summary: 'Editar rendición (solo en BORRADOR)' })
  update(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body(ValidationPipe) dto: UpdateRendicionViaticoDto,
  ) {
    return this.service.update(user.empresa_id, id, dto, user.id);
  }

  @Post(':id/aprobar')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_APROBAR')
  @ApiOperation({ summary: 'Aprobar rendición pendiente' })
  async aprobar(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    const result = await this.service.aprobar(user.empresa_id, id, user.id);
    await this.service.ejecutarImpactosPendientes(user.empresa_id, id, user.id);
    return this.service.findOne(user.empresa_id, id);
  }

  @Post(':id/rechazar')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_APROBAR')
  @ApiOperation({ summary: 'Rechazar rendición pendiente' })
  rechazar(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body() body: { motivo?: string },
  ) {
    return this.service.rechazar(user.empresa_id, id, body?.motivo ?? '', user.id);
  }

  @Post(':id/anular')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_ANULAR')
  @ApiOperation({ summary: 'Anular rendición (revierte adelantos + gastos + cierre)' })
  anular(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body() body: { motivo?: string },
  ) {
    return this.service.anular(user.empresa_id, id, body?.motivo ?? '', user.id);
  }

  @Post(':id/cerrar')
  @RequirePermission('RRHH', 'RH_VIA_CIERRE_EJECUTAR')
  @ApiOperation({ summary: 'Cerrar rendición (registra devolución o reintegro según saldo)' })
  cerrar(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body(ValidationPipe) dto: CerrarRendicionDto,
  ) {
    return this.service.cerrar(user.empresa_id, id, dto, user.id);
  }

  // ── Adelantos ────────────────────────────────────────────────────────────

  @Post(':id/adelantos')
  @RequirePermission('RRHH', 'RH_VIA_RENDICION_CREAR')
  @ApiOperation({ summary: 'Agregar adelanto adicional a rendición existente' })
  async agregarAdelanto(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body(ValidationPipe) dto: CreateAdelantoAdicionalDto,
  ) {
    await this.service.agregarAdelanto(user.empresa_id, id, dto, user.id);
    await this.service.ejecutarImpactosPendientes(user.empresa_id, id, user.id);
    return this.service.findOne(user.empresa_id, id);
  }

  // ── Gastos vinculados (Fase 2) ───────────────────────────────────────────

  @Post(':id/gastos')
  @RequirePermission('RRHH', 'RH_VIA_GASTO_CARGAR')
  @ApiOperation({ summary: 'Agregar gasto (con o sin factura) a la rendición' })
  agregarGasto(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Body(ValidationPipe) dto: CreateGastoRendicionDto,
  ) {
    return this.service.agregarGasto(user.empresa_id, id, dto, user.id);
  }

  @Delete(':id/gastos/:gastoId')
  @RequirePermission('RRHH', 'RH_VIA_GASTO_CARGAR')
  @ApiOperation({ summary: 'Anular gasto vinculado a la rendición' })
  quitarGasto(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Param('gastoId') gastoId: string,
    @Body() body: { motivo?: string } = {},
  ) {
    return this.service.quitarGasto(user.empresa_id, id, gastoId, body?.motivo ?? '', user.id);
  }
}
