import {
  BadRequestException,
  Body,
  Controller,
  Get,
  Param,
  Put,
  Post,
  Query,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { FileInterceptor } from '@nestjs/platform-express';
import {
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
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 {
  AnularDocumentoDto,
  QueryLegajoEmpleadoDto,
  ReemplazarDocumentoDto,
  SubirDocumentoDto,
} from '../dto/legajos.dto';
import { LegajosCompletitudService } from '../services/legajos-completitud.service';
import { LegajosDocumentosService } from '../services/legajos-documentos.service';

const MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024; // hard cap a nivel multipart (25 MB).
// El límite efectivo por empresa lo aplica el service contra el parámetro
// LEGAJO_TAMANIO_MAX_ARCHIVO_MB (default 20). Este cap superior protege contra DoS.

@ApiTags('RRHH - Legajos - Documentos (M24)')
@Controller({ path: 'rrhh/legajos', version: '1' })
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('RRHH')
@ApiBearerAuth()
export class LegajosDocumentosController {
  constructor(
    private readonly documentos: LegajosDocumentosService,
    private readonly completitud: LegajosCompletitudService,
  ) {}

  // ──────────────────────────────────────────────────────────────────────
  // Legajo por funcionario
  // ──────────────────────────────────────────────────────────────────────

  @Get('empleados/:empleadoId')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({
    summary: 'Obtener documentos ACTIVOS del legajo de un funcionario',
  })
  listarPorEmpleado(
    @Param('empleadoId') empleadoId: string,
    @GetUser() user: LoginUserInfo,
    @Query() query: QueryLegajoEmpleadoDto,
  ) {
    return this.documentos.listarLegajoEmpleado(user.empresa_id, empleadoId, query);
  }

  @Get('empleados/:empleadoId/completitud')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({
    summary: 'Reporte de completitud del legajo (tipos obligatorios presentes / faltantes / vencidos)',
  })
  completitudEmpleado(
    @Param('empleadoId') empleadoId: string,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.completitud.generar(user.empresa_id, empleadoId);
  }

  @Get('empleados/:empleadoId/historial')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({
    summary: 'Historial de versiones REEMPLAZADO / ANULADO — sólo AUDITOR y SUPER_ADMIN',
  })
  historialEmpleado(
    @Param('empleadoId') empleadoId: string,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.documentos.obtenerHistorialEmpleado(user.empresa_id, empleadoId);
  }

  // ──────────────────────────────────────────────────────────────────────
  // Carga multipart
  // ──────────────────────────────────────────────────────────────────────

  @Post('empleados/:empleadoId/documentos')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_CREAR')
  @UseInterceptors(FileInterceptor('archivo', { limits: { fileSize: MAX_FILE_SIZE_BYTES } }))
  @ApiOperation({
    summary: 'Cargar nuevo documento al legajo del funcionario',
    description:
      'Multipart/form-data. El archivo va en el campo "archivo" (binario). ' +
      'tipo_documento_id es obligatorio. fecha_vencimiento es obligatoria si el tipo lo requiere. ' +
      'Si ya existe un documento ACTIVO del mismo tipo sin permite_multiples, el anterior pasa a REEMPLAZADO.',
  })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        archivo: { type: 'string', format: 'binary' },
        tipo_documento_id: { type: 'string', format: 'uuid' },
        fecha_documento: { type: 'string', example: '2026-05-01' },
        fecha_vencimiento: { type: 'string', example: '2027-05-01' },
        descripcion: { type: 'string' },
      },
      required: ['archivo', 'tipo_documento_id'],
    },
  })
  subir(
    @Param('empleadoId') empleadoId: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: SubirDocumentoDto,
    @UploadedFile() archivo: Express.Multer.File,
  ) {
    if (!archivo) {
      throw new BadRequestException('Debe adjuntar el archivo en el campo "archivo"');
    }
    return this.documentos.subir(user.empresa_id, empleadoId, dto, archivo, user.id);
  }

  // ──────────────────────────────────────────────────────────────────────
  // Operaciones sobre un documento existente
  // ──────────────────────────────────────────────────────────────────────

  @Get('documentos/:documentoId')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({ summary: 'Obtener metadata de un documento' })
  obtener(@Param('documentoId') documentoId: string, @GetUser() user: LoginUserInfo) {
    return this.documentos.obtener(documentoId, user.empresa_id);
  }

  @Get('documentos/:documentoId/descargar')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({
    summary: 'Generar URL firmada de descarga (Content-Disposition: attachment)',
  })
  descargar(@Param('documentoId') documentoId: string, @GetUser() user: LoginUserInfo) {
    return this.documentos.presignedDownload(documentoId, user.empresa_id);
  }

  @Get('documentos/:documentoId/preview')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_VER')
  @ApiOperation({
    summary: 'Generar URL firmada de preview (Content-Disposition: inline — PDF e imagen)',
  })
  preview(@Param('documentoId') documentoId: string, @GetUser() user: LoginUserInfo) {
    return this.documentos.presignedPreview(documentoId, user.empresa_id);
  }

  @Put('documentos/:documentoId/reemplazar')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_CREAR')
  @UseInterceptors(FileInterceptor('archivo', { limits: { fileSize: MAX_FILE_SIZE_BYTES } }))
  @ApiOperation({
    summary: 'Subir una nueva versión que reemplaza al documento actual',
    description:
      'El documento actual pasa a estado REEMPLAZADO y el nuevo apunta a él vía documento_previo_id. ' +
      'La cadena de versiones queda trazable hacia atrás. No se elimina nada del storage.',
  })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        archivo: { type: 'string', format: 'binary' },
        fecha_documento: { type: 'string', example: '2026-05-01' },
        fecha_vencimiento: { type: 'string', example: '2027-05-01' },
        descripcion: { type: 'string' },
      },
      required: ['archivo'],
    },
  })
  reemplazar(
    @Param('documentoId') documentoId: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: ReemplazarDocumentoDto,
    @UploadedFile() archivo: Express.Multer.File,
  ) {
    if (!archivo) {
      throw new BadRequestException('Debe adjuntar el archivo en el campo "archivo"');
    }
    return this.documentos.reemplazar(documentoId, user.empresa_id, dto, archivo, user.id);
  }

  @Put('documentos/:documentoId/anular')
  @RequirePermission('RRHH', 'RH_LEG_DOCUMENTO_ELIMINAR')
  @ApiOperation({
    summary: 'Anular un documento ACTIVO (requiere motivo)',
    description:
      'El archivo NO se elimina del storage. Sólo SUPER_ADMIN puede anular documentos REEMPLAZADOS ' +
      '(no expuesto en este endpoint).',
  })
  anular(
    @Param('documentoId') documentoId: string,
    @GetUser() user: LoginUserInfo,
    @Body() dto: AnularDocumentoDto,
  ) {
    return this.documentos.anular(documentoId, user.empresa_id, dto, user.id);
  }
}
