import { Body, Controller, Get, Param, Patch, Post, Put, Query, Res, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { GetUser } from 'src/auth/get-user.decorator';
import { RequireModule, RequirePermission } from 'src/auth/decorators';
import { ModuleGuard } from 'src/auth/guards/module.guard';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import {
  AnularOrdenPagoProveedorDto,
  CreateOrdenPagoProveedorDto,
} from './dto/create-orden-pago-proveedor.dto';
import { UpdateConfigComprasDto } from './dto/update-config-compras.dto';
import { RechazarOrdenPagoProveedorDto } from './dto/workflow-orden-pago-proveedor.dto';
import { PagosProveedorService } from './pagos-proveedor.service';

@ApiTags('Pagos Proveedor')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('COMPRAS')
@Controller({ path: 'pagos-proveedor', version: '1' })
export class PagosProveedorController {
  constructor(private readonly pagosProveedorService: PagosProveedorService) {}

  @Post()
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Crear orden de pago a proveedor' })
  create(@Body() dto: CreateOrdenPagoProveedorDto, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.create(dto, user.empresa_id, user.id);
  }

  @Get()
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_VER')
  @ApiOperation({ summary: 'Listar órdenes de pago a proveedores' })
  @ApiQuery({ name: 'page', required: false })
  @ApiQuery({ name: 'limit', required: false })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'proveedor_id', required: false })
  @ApiQuery({ name: 'compra_id', required: false })
  @ApiQuery({ name: 'origen', required: false, description: 'manual | compra_auto' })
  @ApiQuery({ name: 'origen_tipo', required: false, description: 'compra | gasto' })
  @ApiQuery({ name: 'estado', required: false })
  @ApiQuery({ name: 'busqueda', required: false })
  findAll(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('proveedor_id') proveedor_id?: string,
    @Query('compra_id') compra_id?: string,
    @Query('origen') origen?: string,
    @Query('origen_tipo') origen_tipo?: string,
    @Query('estado') estado?: string,
    @Query('busqueda') busqueda?: string,
  ) {
    return this.pagosProveedorService.findAll(user.empresa_id, {
      page,
      limit,
      fecha_desde,
      fecha_hasta,
      proveedor_id,
      compra_id,
      origen,
      origen_tipo,
      estado,
      busqueda,
    });
  }

  @Get('dashboard')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_VER')
  @ApiOperation({ summary: 'Resumen dashboard de órdenes de pago a proveedores' })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'origen', required: false, description: 'manual | compra_auto' })
  @ApiQuery({ name: 'origen_tipo', required: false, description: 'compra | gasto' })
  getDashboard(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('origen') origen?: string,
    @Query('origen_tipo') origen_tipo?: string,
  ) {
    return this.pagosProveedorService.getDashboard(user.empresa_id, {
      fecha_desde,
      fecha_hasta,
      origen,
      origen_tipo,
    });
  }

  @Get('config')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_VER')
  @ApiOperation({ summary: 'Obtener configuración AP (config_compras) de la empresa' })
  getConfig(@GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.getConfigCompras(user.empresa_id);
  }

  @Put('config')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Actualizar configuración AP (config_compras) de la empresa' })
  updateConfig(@GetUser() user: LoginUserInfo, @Body() dto: UpdateConfigComprasDto) {
    return this.pagosProveedorService.updateConfigCompras(user.empresa_id, dto);
  }

  @Get('cuentas-pendientes')
  @RequirePermission('COMPRAS', 'CMP_CXP_CUENTA_PAGAR_VER')
  @ApiOperation({ summary: 'Obtener cuentas por pagar pendientes de un proveedor' })
  @ApiQuery({ name: 'proveedor_id', required: true })
  getCuentasPendientes(@GetUser() user: LoginUserInfo, @Query('proveedor_id') proveedorId: string) {
    return this.pagosProveedorService.getCuentasPendientes(user.empresa_id, proveedorId);
  }

  @Get('cuentas-pagar')
  @RequirePermission('COMPRAS', 'CMP_CXP_CUENTA_PAGAR_VER')
  @ApiOperation({ summary: 'Listar cuentas por pagar' })
  @ApiQuery({ name: 'page', required: false })
  @ApiQuery({ name: 'limit', required: false })
  @ApiQuery({ name: 'fecha_tipo', required: false, description: 'vencimiento | emision' })
  @ApiQuery({ name: 'fecha_desde', required: false, description: 'Filtro por tipo de fecha desde (YYYY-MM-DD)' })
  @ApiQuery({ name: 'fecha_hasta', required: false, description: 'Filtro por tipo de fecha hasta (YYYY-MM-DD)' })
  @ApiQuery({ name: 'proveedor_id', required: false })
  @ApiQuery({ name: 'compra_id', required: false })
  @ApiQuery({ name: 'origen_tipo', required: false, description: 'compra | gasto' })
  @ApiQuery({ name: 'estado', required: false, description: 'pendiente | parcial | pagada | vencida | anulada' })
  @ApiQuery({ name: 'busqueda', required: false, description: 'Factura, razón social o RUC' })
  findCuentasPagar(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('fecha_tipo') fecha_tipo?: string,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('proveedor_id') proveedor_id?: string,
    @Query('compra_id') compra_id?: string,
    @Query('origen_tipo') origen_tipo?: string,
    @Query('estado') estado?: string,
    @Query('busqueda') busqueda?: string,
  ) {
    return this.pagosProveedorService.findCuentasPagar(user.empresa_id, {
      page,
      limit,
      fecha_tipo,
      fecha_desde,
      fecha_hasta,
      proveedor_id,
      compra_id,
      origen_tipo,
      estado,
      busqueda,
    });
  }

  @Get('cuentas-pagar/dashboard')
  @RequirePermission('COMPRAS', 'CMP_CXP_CUENTA_PAGAR_VER')
  @ApiOperation({ summary: 'Resumen dashboard de cuentas por pagar' })
  @ApiQuery({ name: 'fecha_tipo', required: false, description: 'vencimiento | emision' })
  @ApiQuery({ name: 'fecha_desde', required: false, description: 'Filtro por tipo de fecha desde (YYYY-MM-DD)' })
  @ApiQuery({ name: 'fecha_hasta', required: false, description: 'Filtro por tipo de fecha hasta (YYYY-MM-DD)' })
  @ApiQuery({ name: 'origen_tipo', required: false, description: 'compra | gasto' })
  getCuentasPagarDashboard(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_tipo') fecha_tipo?: string,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('origen_tipo') origen_tipo?: string,
  ) {
    return this.pagosProveedorService.getCuentasPagarDashboard(user.empresa_id, {
      fecha_tipo,
      fecha_desde,
      fecha_hasta,
      origen_tipo,
    });
  }

  @Patch(':id/anular')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_ANULAR')
  @ApiOperation({ summary: 'Anular orden de pago y revertir impacto en cuentas por pagar' })
  anular(
    @Param('id') id: string,
    @Body() dto: AnularOrdenPagoProveedorDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.pagosProveedorService.anular(id, dto, user.empresa_id, user.id);
  }

  @Patch(':id/enviar-aprobacion')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Enviar orden de pago a aprobación' })
  enviarAprobacion(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.enviarAprobacion(id, user.empresa_id, user.id);
  }

  @Patch(':id/aprobar')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_APROBAR')
  @ApiOperation({ summary: 'Aprobar orden de pago pendiente de aprobación' })
  aprobar(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.aprobar(id, user.empresa_id, user.id);
  }

  @Patch(':id/rechazar')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_APROBAR')
  @ApiOperation({ summary: 'Rechazar orden de pago pendiente de aprobación' })
  rechazar(@Param('id') id: string, @Body() dto: RechazarOrdenPagoProveedorDto, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.rechazar(id, dto.motivo, user.empresa_id, user.id);
  }

  @Post(':id/ejecutar')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Ejecutar una orden BORRADOR y aplicar el pago en cuentas por pagar' })
  ejecutar(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.ejecutar(id, user.empresa_id, user.id);
  }

  @Post(':id/reintentar-contabilidad')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Reintentar integración contable de la orden de pago (estado PAGADO)' })
  reintentarContabilidad(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.reintentarContabilidad(id, user.empresa_id);
  }

  @Post(':id/reintentar-tesoreria')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_CREAR')
  @ApiOperation({ summary: 'Reintentar el registro del egreso en Tesorería de la orden de pago (estado PAGADO/APLICADO)' })
  reintentarTesoreria(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.reintentarTesoreria(id, user.empresa_id, user.id);
  }

  @Get(':id')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_VER')
  @ApiOperation({ summary: 'Obtener detalle de orden de pago a proveedor' })
  findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.findOne(id, user.empresa_id);
  }

  @Get('cuentas-pagar/estado-cuenta/:proveedorId')
  @RequirePermission('COMPRAS', 'CMP_CXP_CUENTA_PAGAR_VER')
  @ApiOperation({ summary: 'Estado de cuenta de un proveedor (JSON)' })
  getEstadoCuentaProveedor(@Param('proveedorId') proveedorId: string, @GetUser() user: LoginUserInfo) {
    return this.pagosProveedorService.getEstadoCuentaProveedor(user.empresa_id, proveedorId, user.id);
  }

  @Get('cuentas-pagar/estado-cuenta/:proveedorId/pdf')
  @RequirePermission('COMPRAS', 'CMP_CXP_CUENTA_PAGAR_VER')
  @ApiOperation({ summary: 'Generar PDF de estado de cuenta de un proveedor' })
  @ApiQuery({ name: 'tipo', required: false, enum: ['view', 'base64'] })
  @ApiQuery({ name: 'incluir_todas', required: false, description: 'Incluir cuotas no vencidas' })
  async getEstadoCuentaProveedorPdf(
    @Param('proveedorId') proveedorId: string,
    @GetUser() user: LoginUserInfo,
    @Query('tipo') tipo?: string,
    @Query('incluir_todas') incluirTodas?: string,
    @Res() res?: any,
  ) {
    const result = await this.pagosProveedorService.generateEstadoCuentaProveedorPdf(user.empresa_id, proveedorId, {
      tipo_retorno: tipo || 'view',
      incluir_todas: incluirTodas === 'true' || incluirTodas === '1',
      usuarioId: user.id,
    });
    if (result.base64) return res.json({ status: 'success', pdf_base64: result.base64 });
    res.set({
      'Content-Type': result.contentType,
      'Content-Disposition': `inline; filename="estado-cuenta-proveedor-${proveedorId}.pdf"`,
      'Content-Length': result.pdfBuffer.length,
    });
    return res.send(result.pdfBuffer);
  }

  @Get(':id/pdf')
  @RequirePermission('COMPRAS', 'CMP_OP_ORDEN_PAGO_VER')
  @ApiOperation({ summary: 'Generar PDF A4 de una orden de pago a proveedor' })
  async getPdf(@Param('id') id: string, @GetUser() user: LoginUserInfo, @Res() res: any) {
    const result = await this.pagosProveedorService.generatePdf(id, user.empresa_id);

    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `inline; filename="${result.filename}"`,
      'Content-Length': result.pdfBuffer.length,
    });

    return res.send(result.pdfBuffer);
  }
}
