import {
    Body,
    Controller,
    Get,
    HttpException,
    HttpStatus,
    Param,
    Patch,
    Post,
    Query,
    Res,
    UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiBody, ApiCreatedResponse, ApiOperation, ApiParam, ApiQuery } from '@nestjs/swagger';
import type { Response } from 'express';
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 { KudeService } from 'src/kude/kude.service';
import { AnularFacturaDto, EnviarLoteMiddlewareDto } from './dto/anular-factura.dto';
import { CreateFacturaAutoDto } from './dto/create-factura-auto.dto';
import { CreateFacturaDto } from './dto/create-factura.dto';
import {
    response_factura_all,
    response_factura_create,
    response_factura_find,
    response_factura_siguiente_numeracion,
} from './dto/doc-swagger';
import { FacturasService } from './facturas.service';

@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('VENTAS')
@Controller({ path: 'facturas', version: '1' })
export class FacturasController {
  constructor(
    private readonly facturasService: FacturasService,
    private readonly kudeService: KudeService,
  ) {}

  @Post('automatico')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_CREAR')
  @ApiBody({ type: CreateFacturaAutoDto })
  @ApiCreatedResponse(response_factura_create)
  createFacturaAutomatico(@Body() createFacturaAutoDto: CreateFacturaAutoDto, @GetUser() user: LoginUserInfo) {
    return this.facturasService.createFacturaAutomatico(createFacturaAutoDto, user.empresa_id, user?.id);
  }

  @Post()
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_CREAR')
  @ApiBody({ type: CreateFacturaDto })
  @ApiCreatedResponse(response_factura_create)
  create(@Body() createFacturaDto: CreateFacturaDto, @GetUser() user: LoginUserInfo) {
    return this.facturasService.create(createFacturaDto, user.empresa_id, user?.id);
  }

  @Get('reporte/productos')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Reporte de ventas por producto' })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'categoria_id', required: false })
  @ApiQuery({ name: 'moneda_id', required: false })
  @ApiQuery({ name: 'limit', required: false })
  @ApiQuery({ name: 'rubro_id', required: false })
  @ApiQuery({ name: 'producto_id', required: false })
  @ApiQuery({ name: 'cliente_id', required: false })
  async getReporteProductos(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('categoria_id') categoria_id?: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('limit') limit?: string,
    @Query('rubro_id') rubro_id?: string,
    @Query('producto_id') producto_id?: string,
    @Query('cliente_id') cliente_id?: string,
  ) {
    return this.facturasService.getReporteProductos(
      user.empresa_id,
      {
        fecha_desde,
        fecha_hasta,
        categoria_id,
        moneda_id,
        rubro_id,
        producto_id,
        cliente_id,
        limit: limit ? Number(limit) : 50,
      },
      user.id,
    );
  }

  @Get('reporte/productos/detalle')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Ventas por producto: detalle por línea de factura' })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'categoria_id', required: false })
  @ApiQuery({ name: 'moneda_id', required: false })
  @ApiQuery({ name: 'rubro_id', required: false })
  @ApiQuery({ name: 'producto_id', required: false })
  @ApiQuery({ name: 'cliente_id', required: false })
  @ApiQuery({ name: 'page', required: false })
  @ApiQuery({ name: 'limit', required: false })
  async getReporteProductosDetalle(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('categoria_id') categoria_id?: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('rubro_id') rubro_id?: string,
    @Query('producto_id') producto_id?: string,
    @Query('cliente_id') cliente_id?: string,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
  ) {
    return this.facturasService.getReporteProductosDetalle(
      user.empresa_id,
      { fecha_desde, fecha_hasta, categoria_id, moneda_id, rubro_id, producto_id, cliente_id, page: Number(page) || 1, limit: Number(limit) || 100 },
      user.id,
    );
  }

  @Get('reporte/clientes')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Clientes con movimiento (ventas y/o pagos) en un rango de fechas' })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  async getReporteClientes(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
  ) {
    return this.facturasService.getReporteClientes(
      user.empresa_id,
      {
        fecha_desde,
        fecha_hasta,
      },
      user.id,
    );
  }

  @Get('liquidacion-iva')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Liquidación IVA - IVA Débito vs Crédito del período' })
  @ApiQuery({ name: 'mes', required: true })
  @ApiQuery({ name: 'anio', required: true })
  @ApiQuery({ name: 'moneda_id', required: false })
  async getLiquidacionIva(
    @GetUser() user: LoginUserInfo,
    @Query('mes') mes: string,
    @Query('anio') anio: string,
    @Query('moneda_id') moneda_id?: string,
  ) {
    return this.facturasService.getLiquidacionIva(user.empresa_id, Number(mes), Number(anio), moneda_id, user.id);
  }

  @Get('libro-iva-ventas')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Libro IVA Ventas - Reporte fiscal' })
  @ApiQuery({ name: 'mes', required: true, description: 'Mes (1-12)' })
  @ApiQuery({ name: 'anio', required: true, description: 'Año' })
  @ApiQuery({ name: 'moneda_id', required: false, description: 'Filtrar por moneda' })
  async getLibroIvaVentas(
    @GetUser() user: LoginUserInfo,
    @Query('mes') mes: string,
    @Query('anio') anio: string,
    @Query('moneda_id') moneda_id?: string,
  ) {
    return this.facturasService.getLibroIvaVentas(user.empresa_id, Number(mes), Number(anio), moneda_id, user.id);
  }

  @Get('libro-iva-ventas/marangatu')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Libro IVA Ventas - Export importable en Marangatu (Registro de Comprobantes)' })
  @ApiQuery({ name: 'mes', required: true, description: 'Mes (1-12)' })
  @ApiQuery({ name: 'anio', required: true, description: 'Año' })
  @ApiQuery({ name: 'moneda_id', required: false })
  @ApiQuery({ name: 'secuencia', required: false, description: 'Identificador del archivo (<=5 alfanum.)' })
  async getLibroIvaVentasMarangatu(
    @GetUser() user: LoginUserInfo,
    @Query('mes') mes: string,
    @Query('anio') anio: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('secuencia') secuencia?: string,
  ) {
    return this.facturasService.getLibroIvaVentasMarangatu(
      user.empresa_id,
      Number(mes),
      Number(anio),
      moneda_id,
      secuencia || undefined,
      user.id,
    );
  }

  @Get('siguiente-numeracion/:est/:exp')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiParam({
    name: 'est',
    type: 'string',
    required: false,
    description: 'Establecimiento',
  })
  @ApiParam({
    name: 'exp',
    type: 'string',
    required: false,
    description: 'Expresion',
  })
  @ApiCreatedResponse(response_factura_siguiente_numeracion)
  getSiguienteNumeracion(@Param('est') est: string, @Param('exp') exp: string, @GetUser() user: LoginUserInfo) {
    return this.facturasService.getSiguienteNumeracion(est, exp, user.empresa_id);
  }

  @Get('pendientes-envio/lista')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiQuery({ name: 'page', type: 'string', required: false })
  @ApiQuery({ name: 'limit', type: 'string', required: false })
  async getPendientesEnvio(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
  ) {
    try {
      const result = await this.facturasService.findPendientesEnvio(
        Number(page) || 1,
        Number(limit) || 50,
        user.empresa_id,
      );
      return {
        message: 'Facturas pendientes de envío obtenidas exitosamente',
        ...result,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al obtener facturas pendientes',
          error: errorMessage,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Get('resumen')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiQuery({
    name: 'page',
    type: 'string',
    required: false,
    description: 'Página actual',
  })
  @ApiQuery({
    name: 'limit',
    type: 'string',
    required: false,
    description: 'Límite por página',
  })
  @ApiQuery({
    name: 'fecha_desde',
    type: 'string',
    required: false,
    description: 'Fecha desde (YYYY-MM-DD)',
  })
  @ApiQuery({
    name: 'fecha_hasta',
    type: 'string',
    required: false,
    description: 'Fecha hasta (YYYY-MM-DD)',
  })
  @ApiQuery({
    name: 'estado',
    type: 'string',
    required: false,
    description: 'Estado: pendiente, pagada, anulada, vencida',
  })
  @ApiQuery({
    name: 'cliente_id',
    type: 'string',
    required: false,
    description: 'ID del cliente',
  })
  @ApiQuery({
    name: 'search',
    type: 'string',
    required: false,
    description: 'Búsqueda por número o cliente',
  })
  @ApiQuery({
    name: 'sucursal_id',
    type: 'string',
    required: false,
    description: 'ID de la sucursal',
  })
  @ApiQuery({
    name: 'estado_sifen',
    type: 'string',
    required: false,
    description: 'Estado SIFEN: Aprobado, Rechazado, Pendiente',
  })
  async getResumen(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fechaDesde?: string,
    @Query('fecha_hasta') fechaHasta?: string,
    @Query('estado') estado?: string,
    @Query('cliente_id') clienteId?: string,
    @Query('search') search?: string,
    @Query('sucursal_id') sucursalId?: string,
    @Query('estado_sifen') estadoSifen?: string,
    @Query('sesion_caja_id') sesionCajaId?: string,
  ) {
    return this.facturasService.getResumen(user.empresa_id, {
      fechaDesde,
      fechaHasta,
      estado,
      clienteId,
      search,
      sucursalId,
      estadoSifen,
      sesionCajaId,
      usuarioId: user.id,
    });
  }

  @Get('dashboard')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Métricas de ventas para el dashboard (agregado filter-wide)' })
  @ApiQuery({ name: 'fecha_desde', required: false, description: 'Período actual desde (YYYY-MM-DD)' })
  @ApiQuery({ name: 'fecha_hasta', required: false, description: 'Período actual hasta (YYYY-MM-DD)' })
  @ApiQuery({ name: 'fecha_desde_anterior', required: false, description: 'Período anterior desde (YYYY-MM-DD)' })
  @ApiQuery({ name: 'fecha_hasta_anterior', required: false, description: 'Período anterior hasta (YYYY-MM-DD)' })
  @ApiQuery({ name: 'moneda_id', required: false, description: 'Filtrar por moneda; sin este valor convierte todo a PYG' })
  async getDashboardVentas(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fechaDesde?: string,
    @Query('fecha_hasta') fechaHasta?: string,
    @Query('fecha_desde_anterior') fechaDesdeAnterior?: string,
    @Query('fecha_hasta_anterior') fechaHastaAnterior?: string,
    @Query('moneda_id') monedaId?: string,
  ) {
    return this.facturasService.getDashboardVentas(user.empresa_id, {
      fechaDesde,
      fechaHasta,
      fechaDesdeAnterior,
      fechaHastaAnterior,
      monedaId: monedaId && monedaId !== 'todas' ? monedaId : undefined,
      usuarioId: user.id,
    });
  }

  @Get()
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiCreatedResponse(response_factura_all)
  async findAll(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('fecha_desde') fechaDesde?: string,
    @Query('fecha_hasta') fechaHasta?: string,
    @Query('estado') estado?: string,
    @Query('cliente_id') clienteId?: string,
    @Query('search') search?: string,
    @Query('sucursal_id') sucursalId?: string,
    @Query('estado_sifen') estadoSifen?: string,
    @Query('sesion_caja_id') sesionCajaId?: string,
  ) {
    try {
      const filters = {
        fechaDesde,
        fechaHasta,
        estado,
        clienteId,
        search,
        sucursalId,
        estadoSifen,
        sesionCajaId,
        usuarioId: user.id,
      };
      const {
        items,
        total,
        page: currentPage,
        limit: pageLimit,
        lastPage,
      } = await this.facturasService.findAll(Number(page) || 1, Number(limit) || 10, user.empresa_id, filters);

      return {
        message: 'Facturas obtenidas exitosamente',
        data: items,
        total,
        page: currentPage,
        limit: pageLimit,
        lastPage,
      };
    } catch (error) {
      console.log(error);
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al obtener facturas',
          error: errorMessage,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @ApiParam({
    name: 'cdc',
    type: 'string',
    required: true,
    description: 'CDC del documento (44 dígitos)',
  })
  @Get('consulta/:cdc/pdf')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_IMPRIMIR')
  @ApiOperation({
    summary: 'Obtener PDF (KUDE) de un documento por CDC (público)',
  })
  async getPdfByCdc(@Param('cdc') cdc: string, @Query('ticket') ticket: string, @Res() res: Response) {
    try {
      const { id, empresa_id } = await this.facturasService.findIdByCdc(cdc);
      const isTicket = ticket === 'true' || ticket === '1';
      const result = await this.kudeService.generateKudeFactura(id, empresa_id, {
        ticket: isTicket,
        tipo_retorno: 'view',
      });
      res.set({
        'Content-Type': 'application/pdf',
        'Content-Disposition': `inline; filename="${cdc}.pdf"`,
      });
      if (result.pdfBuffer) {
        res.send(result.pdfBuffer);
      }
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al generar PDF del documento',
          error: errorMessage,
        },
        error instanceof HttpException ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @ApiParam({
    name: 'cdc',
    type: 'string',
    required: true,
    description: 'CDC del documento (44 dígitos)',
  })
  @Get('consulta/:cdc')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  async findByCdc(@Param('cdc') cdc: string) {
    try {
      return await this.facturasService.findByCdc(cdc);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al consultar documento',
          error: errorMessage,
        },
        error instanceof HttpException ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Get('ultimo-precio')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiOperation({ summary: 'Último precio de un producto para un cliente' })
  @ApiQuery({ name: 'cliente_id', required: true })
  @ApiQuery({ name: 'producto_id', required: true })
  async getUltimoPrecioCliente(
    @GetUser() user: LoginUserInfo,
    @Query('cliente_id') clienteId: string,
    @Query('producto_id') productoId: string,
  ) {
    return this.facturasService.getUltimoPrecioCliente(user.empresa_id, clienteId, productoId);
  }

  @Get(':id')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  @ApiCreatedResponse(response_factura_find)
  findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.facturasService.findOne(id, user.empresa_id);
  }

  @Get(':id/documentos-vinculados')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_VER')
  getDocumentosVinculados(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.facturasService.getDocumentosVinculados(id, user.empresa_id);
  }

  @Post('enviar-lote-middleware')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_CREAR')
  @ApiBody({
    description: 'IDs de facturas a enviar al middleware',
    schema: {
      type: 'object',
      properties: {
        factura_ids: { type: 'array', items: { type: 'string' } },
      },
    },
  })
  async enviarLoteMiddleware(@Body() body: EnviarLoteMiddlewareDto, @GetUser() user: LoginUserInfo) {
    try {
      const result = await this.facturasService.enviarLoteMiddleware(body.factura_ids, user.empresa_id, user?.id);
      return {
        message: 'Facturas enviadas al middleware exitosamente',
        data: result,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al enviar facturas al middleware',
          error: errorMessage,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Patch(':id/anular')
  @RequirePermission('VENTAS', 'VEN_FAC_FACTURA_ANULAR')
  @ApiOperation({ summary: 'Anular una factura (retail)' })
  @ApiParam({ name: 'id', description: 'ID de la factura a anular' })
  anularFactura(
    @Param('id') id: string,
    @GetUser() user: LoginUserInfo,
    @Body() body: AnularFacturaDto,
  ) {
    return this.facturasService.anularFactura(id, user.empresa_id, {
      motivo: body.motivo,
      token_autorizacion: body.token_autorizacion,
      user_id: user.id,
    });
  }
}
