import { Body, Controller, Get, Param, Post, Query, Res, UseGuards, ValidationPipe } from '@nestjs/common';
import type { Response } from 'express';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import type { LoginUserInfo } from '../auth/dto/login.dto';
import { GetUser } from '../auth/get-user.decorator';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { PermissionGuard } from '../auth/guards/permission.guard';
import { AbrirCajaDto } from './dto/abrir-caja.dto';
import { CerrarCajaDto } from './dto/cerrar-caja.dto';
import { MovimientoCajaDto } from './dto/movimiento-caja.dto';
import { TesoreriaService } from './tesoreria.service';

@ApiTags('Tesorería')
@Controller({ version: '1', path: 'tesoreria' })
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
export class TesoreriaController {
  constructor(private readonly tesoreriaService: TesoreriaService) {}

  // ==================== SESIONES DE CAJA ====================

  @Post('caja/abrir')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ABRIR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Abrir caja' })
  abrirCaja(@Body(ValidationPipe) dto: AbrirCajaDto, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.abrirCaja(dto, user.empresa_id, user.id);
  }

  @Post('caja/cerrar/:sesion_id')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_CERRAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Cerrar caja y hacer arqueo' })
  cerrarCaja(
    @Param('sesion_id') sesion_id: string,
    @Body(ValidationPipe) dto: CerrarCajaDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.tesoreriaService.cerrarCaja(sesion_id, dto, user.empresa_id, user.id);
  }

  @Get('caja/activa')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Obtener sesión de caja activa' })
  @ApiQuery({ name: 'caja_id', required: false })
  getSesionActiva(@GetUser() user: LoginUserInfo, @Query('caja_id') caja_id?: string) {
    return this.tesoreriaService.getSesionActiva(user.empresa_id, caja_id, user.id);
  }

  @Get('caja/abiertas')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Obtener todas las sesiones de caja abiertas de la empresa' })
  getSesionesAbiertas(@GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.getSesionesAbiertas(user.empresa_id, user.id);
  }

  @Get('caja/historial')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Historial de sesiones de caja' })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  @ApiQuery({ name: 'caja_id', required: false })
  getSesionesHistorial(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('caja_id') caja_id?: string,
  ) {
    return this.tesoreriaService.getSesionesHistorial(
      user.empresa_id,
      page ? parseInt(page) : 1,
      limit ? parseInt(limit) : 20,
      caja_id,
    );
  }

  @Get('caja/sesion/:sesion_id')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Detalle de una sesión de caja' })
  getSesionDetalle(@Param('sesion_id') sesion_id: string, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.getSesionDetalle(sesion_id, user.empresa_id);
  }

  @Get('cajas-disponibles')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Listar cajas disponibles con estado de sesión' })
  getCajasDisponibles(@GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.getCajasDisponibles(user.empresa_id, user.id);
  }

  // ==================== CIERRE ESTRICTO ====================

  @Post('caja/iniciar-cierre/:sesion_id')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_CERRAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Iniciar proceso de cierre (bloquea caja)' })
  iniciarCierre(@Param('sesion_id') sesion_id: string, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.iniciarCierre(sesion_id, user.empresa_id, user.id);
  }

  @Post('caja/cancelar-cierre/:sesion_id')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_CERRAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Cancelar proceso de cierre (desbloquea caja)' })
  cancelarCierre(
    @Param('sesion_id') sesion_id: string,
    @Body('token_autorizacion') token_autorizacion: string,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.tesoreriaService.cancelarCierre(sesion_id, user.empresa_id, user.id, token_autorizacion);
  }

  // ==================== MOVIMIENTOS ====================

  @Post('movimiento')
  @RequirePermission('TESORERIA', 'TES_MOV_MOVIMIENTO_CREAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Registrar entrada o salida de caja' })
  registrarMovimiento(@Body(ValidationPipe) dto: MovimientoCajaDto, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.registrarMovimiento(dto, user.empresa_id, user.id);
  }

  @Get('movimientos')
  @RequirePermission('TESORERIA', 'TES_MOV_MOVIMIENTO_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Listar movimientos de caja' })
  @ApiQuery({ name: 'sesion_id', required: false })
  @ApiQuery({ name: 'caja_id', required: false })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  @ApiQuery({ name: 'desde', required: false })
  @ApiQuery({ name: 'hasta', required: false })
  @ApiQuery({ name: 'search', required: false })
  @ApiQuery({ name: 'medio_pago_id', required: false })
  getMovimientos(
    @GetUser() user: LoginUserInfo,
    @Query('sesion_id') sesion_id?: string,
    @Query('caja_id') caja_id?: string,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('desde') desde?: string,
    @Query('hasta') hasta?: string,
    @Query('search') search?: string,
    @Query('medio_pago_id') medio_pago_id?: string,
  ) {
    return this.tesoreriaService.getMovimientos(user.empresa_id, {
      sesion_id,
      caja_id,
      page: page ? parseInt(page) : 1,
      limit: limit ? parseInt(limit) : 20,
      desde,
      hasta,
      search,
      medio_pago_id,
      usuarioId: user.id,
    });
  }

  // ==================== ARQUEOS ====================

  @Get('arqueos')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ARQUEAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Historial de arqueos' })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  @ApiQuery({ name: 'caja_id', required: false })
  getArqueos(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('caja_id') caja_id?: string,
  ) {
    return this.tesoreriaService.getArqueos(
      user.empresa_id,
      page ? parseInt(page) : 1,
      limit ? parseInt(limit) : 20,
      caja_id,
    );
  }

  // ==================== FASE 1: ARQUEO STANDALONE ====================

  @Post('arqueo/:sesion_id')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ARQUEAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Crear arqueo parcial para sesión abierta' })
  crearArqueo(@Param('sesion_id') sesion_id: string, @Body(ValidationPipe) dto: any, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.crearArqueo(sesion_id, dto, user.empresa_id, user.id);
  }

  @Get('arqueo/:arqueo_id/detalle')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ARQUEAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Obtener detalle de un arqueo' })
  getArqueoDetalle(@Param('arqueo_id') arqueo_id: string, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.getArqueoDetalle(arqueo_id, user.empresa_id);
  }

  @Get('caja/sesion/:sesion_id/arqueo/pdf')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ARQUEAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'PDF de arqueo/cierre de una sesión de caja' })
  @ApiQuery({ name: 'formato', required: false, enum: ['a4', 'ticket', 'ticket-detallado', 'a4-detallado'] })
  @ApiQuery({ name: 'arqueo_id', required: false })
  async getArqueoSesionPdf(
    @Param('sesion_id') sesion_id: string,
    @Query('formato') formato: 'a4' | 'ticket' | 'ticket-detallado' | 'a4-detallado' = 'a4',
    @Query('arqueo_id') arqueo_id: string | undefined,
    @GetUser() user: LoginUserInfo,
    @Res() res: Response,
  ) {
    const { pdfBuffer, fileName } = await this.tesoreriaService.generarPdfArqueoSesion(
      sesion_id,
      user.empresa_id,
      formato,
      arqueo_id,
    );
    res.writeHead(200, {
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${fileName}"`,
      'Content-Length': pdfBuffer.length,
    });
    return res.end(pdfBuffer);
  }

  @Get('arqueo/:arqueo_id/pdf')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_ARQUEAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'PDF de un arqueo específico' })
  @ApiQuery({ name: 'formato', required: false, enum: ['a4', 'ticket', 'ticket-detallado', 'a4-detallado'] })
  async getArqueoPdf(
    @Param('arqueo_id') arqueo_id: string,
    @Query('formato') formato: 'a4' | 'ticket' | 'ticket-detallado' | 'a4-detallado' = 'a4',
    @GetUser() user: LoginUserInfo,
    @Res() res: Response,
  ) {
    const { pdfBuffer, fileName } = await this.tesoreriaService.generarPdfArqueo(
      arqueo_id,
      user.empresa_id,
      formato,
    );
    res.writeHead(200, {
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${fileName}"`,
      'Content-Length': pdfBuffer.length,
    });
    return res.end(pdfBuffer);
  }

  // ==================== FASE 1: DOCUMENTOS POR SESIÓN ====================

  @Post('sesion/:sesion_id/documentos')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_EDITAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Asignar tipos de documento a una sesión de caja' })
  asignarDocumentos(
    @Param('sesion_id') sesion_id: string,
    @Body('documentos') documentos: { tipo_documento_id: string; numeracion_id?: string }[],
    @GetUser() user: LoginUserInfo,
  ) {
    return this.tesoreriaService.asignarDocumentosSesion(sesion_id, documentos, user.empresa_id);
  }

  @Get('sesion/:sesion_id/documentos')
  @RequirePermission('TESORERIA', 'TES_CAJ_CAJA_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Obtener documentos asignados a una sesión' })
  getDocumentosSesion(@Param('sesion_id') sesion_id: string, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.getDocumentosSesion(sesion_id, user.empresa_id);
  }

  // ==================== FASE 1: DISPOSITIVOS ====================

  @Get('dispositivos')
  @RequirePermission('TESORERIA', 'TES_PAR_PARAMETRO_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Listar dispositivos autorizados' })
  @ApiQuery({ name: 'caja_id', required: false })
  getDispositivos(@GetUser() user: LoginUserInfo, @Query('caja_id') caja_id?: string) {
    return this.tesoreriaService.getDispositivos(user.empresa_id, caja_id);
  }

  @Post('dispositivos/:id/revocar')
  @RequirePermission('TESORERIA', 'TES_PAR_PARAMETRO_CONFIGURAR')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Revocar un dispositivo autorizado' })
  revocarDispositivo(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.tesoreriaService.revocarDispositivo(id, user.empresa_id);
  }

  // ==================== FASE 1: POS CONFIG ====================

  @Get('pos-config/:caja_id')
  @RequirePermission('TESORERIA', 'TES_PAR_PARAMETRO_VER')
  @UseGuards(PermissionGuard)
  @ApiOperation({ summary: 'Obtener configuración POS de una caja' })
  getPosConfig(@Param('caja_id') caja_id: string) {
    return this.tesoreriaService.getPosConfig(caja_id);
  }
}
