import {
  Patch,
  BadRequestException,
  Body,
  Controller,
  Get,
  Param,
  Post,
  Query,
  Res,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { AuthGuard } from '@nestjs/passport';
import {
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
  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 {
  AjustarMarcacionLimpiaDto,
  ImportarMarcacionesDto,
  QueryBatchesDto,
  QueryLogCorreccionesDto,
  QueryMarcacionesDto,
  QueryMarcacionesLimpiasDto,
} from '../dto/marcaciones.dto';
import { MarcacionesService } from '../services/marcaciones.service';

@ApiTags('RRHH - Presentismo - Marcaciones')
@Controller({ path: 'rrhh/presentismo', version: '1' })
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('RRHH')
@ApiBearerAuth()
export class MarcacionesController {
  constructor(private readonly service: MarcacionesService) {}

  // ────────── Ingesta ─────────────────────────────────────────────

  @Get('marcaciones/plantilla')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_EXPORTAR')
  @ApiOperation({
    summary: 'Descargar plantilla Excel para importación de marcaciones',
    description:
      'Descarga un .xlsx con hoja de instrucciones y dos formatos soportados: ' +
      '(A) POR_DIA y (B) POR_MARCACION.',
  })
  descargarPlantilla(@Res() res: Response) {
    const buffer = this.service.generarPlantillaImportacionExcel();
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res.setHeader('Content-Disposition', 'attachment; filename="plantilla_marcaciones_presentismo.xlsx"');
    res.send(buffer);
  }

  @Post('marcaciones/importar')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_CREAR')
  @UseInterceptors(FileInterceptor('archivo'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        archivo: { type: 'string', format: 'binary' },
        reloj_id: { type: 'string', format: 'uuid' },
      },
    },
  })
  @ApiOperation({
    summary: 'Importar marcaciones desde planilla CSV/Excel',
    description:
      'Acepta dos formatos: (A) documento_funcionario, fecha, hora_entrada, hora_salida; ' +
      '(B) documento_funcionario, timestamp_marcacion. Las filas inválidas se reportan ' +
      'en el response pero no abortan el lote. Después de la ingesta se ejecuta la ' +
      'deduplicación automáticamente.',
  })
  importarPlanilla(
    @GetUser() user: LoginUserInfo,
    @UploadedFile() file: Express.Multer.File,
    @Body() body: ImportarMarcacionesDto,
  ) {
    if (!file) throw new BadRequestException('Falta el archivo (campo "archivo")');
    return this.service.importarPlanilla(user.empresa_id, file.buffer, {
      reloj_id: body.reloj_id,
      userId: user.id,
    });
  }

  // ────────── Consultas ───────────────────────────────────────────

  @Get('marcaciones')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({ summary: 'Listar marcaciones crudas (raw) con filtros' })
  listarRaw(@GetUser() user: LoginUserInfo, @Query() query: QueryMarcacionesDto) {
    return this.service.listarRaw(user.empresa_id, query);
  }

  @Get('marcaciones/limpias')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({
    summary: 'Listar marcaciones limpias (una por empleado/día)',
    description: 'Tabla resultante de la deduplicación. Fuente de verdad para el motor de novedades.',
  })
  listarLimpias(@GetUser() user: LoginUserInfo, @Query() query: QueryMarcacionesLimpiasDto) {
    return this.service.listarLimpias(user.empresa_id, query);
  }

  @Patch('marcaciones/limpias/:id')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_EDITAR')
  @ApiOperation({
    summary: 'Ajustar manualmente una marcación limpia',
    description:
      'Permite corregir hora_entrada/hora_salida/turno. Siempre registra auditoría en ' +
      'rrhh_marcaciones_ajustes_manuales y marca procesado_novedades=false.',
  })
  ajustarLimpia(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Body() body: AjustarMarcacionLimpiaDto,
  ) {
    return this.service.ajustarLimpia(id, user.empresa_id, body, user.id);
  }

  @Get('marcaciones/batches')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({ summary: 'Listar lotes de importación con resumen por estado' })
  listarBatches(@GetUser() user: LoginUserInfo, @Query() query: QueryBatchesDto) {
    return this.service.listarBatches(user.empresa_id, query);
  }

  @Get('marcaciones/batches/:id')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({ summary: 'Detalle de un lote de importación (incluye filas con error)' })
  obtenerBatch(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.obtenerBatch(user.empresa_id, id);
  }

  // ────────── Log de correcciones (auditoría inmutable) ──────────

  @Get('log-correcciones')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({
    summary: 'Listar log de correcciones de la deduplicación',
    description: 'Auditoría inmutable: no expone DELETE/UPDATE.',
  })
  listarLogCorrecciones(
    @GetUser() user: LoginUserInfo,
    @Query() query: QueryLogCorreccionesDto,
  ) {
    return this.service.listarLogCorrecciones(user.empresa_id, query);
  }

  @Get('log-correcciones/:id')
  @RequirePermission('RRHH', 'RH_MAR_MARCACION_VER')
  @ApiOperation({ summary: 'Detalle de una corrección de deduplicación' })
  obtenerLogCorreccion(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.obtenerLogCorreccion(user.empresa_id, id);
  }
}
