import { BadRequestException, Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, UseGuards, UseInterceptors } 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 { Auditable } from 'src/audit/auditable.decorator';
import { AuditInterceptor } from 'src/audit/audit.interceptor';
import { CreateCompraDto } from './dto/create-compra.dto';
import { UpdateCompraDto } from './dto/update-compra.dto';
import { UpsertConfigComprasMonedaDto } from './dto/config-compras-moneda.dto';
import { ComprasService, tipoComprobanteLibro } from './compras.service';

@ApiTags('Compras')
@Controller({ path: 'compras', version: '1' })
export class ComprasController {
  constructor(private readonly comprasService: ComprasService) {}

  @Post()
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Crear factura de compra' })
  @Auditable('compra')
  @UseInterceptors(AuditInterceptor)
  create(@Body() dto: CreateCompraDto, @GetUser() user: LoginUserInfo) {
    return this.comprasService.create(dto, user.empresa_id, user.id);
  }

  @Get()
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Listar compras (paginado con filtros)' })
  @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: 'sucursal_id', required: false })
  @ApiQuery({ name: 'deposito_id', required: false })
  @ApiQuery({ name: 'producto_id', required: false })
  @ApiQuery({ name: 'search', required: false })
  @ApiQuery({ name: 'estado', 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('sucursal_id') sucursal_id?: string,
    @Query('deposito_id') deposito_id?: string,
    @Query('producto_id') producto_id?: string,
    @Query('search') search?: string,
    @Query('estado') estado?: string,
  ) {
    return this.comprasService.findAll(user.empresa_id, {
      page,
      limit,
      fecha_desde,
      fecha_hasta,
      proveedor_id,
      sucursal_id,
      deposito_id,
      producto_id,
      search,
      estado,
      usuarioId: user.id,
    });
  }

  @Get('proveedores/search')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Búsqueda/listado de proveedores para compras' })
  @ApiQuery({ name: 'q', required: false })
  @ApiQuery({ name: 'limit', required: false })
  @ApiQuery({
    name: 'rubro_id',
    required: false,
    description: 'Rubro en contexto. Incluye los proveedores sin rubro asignado.',
  })
  searchProveedores(
    @GetUser() user: LoginUserInfo,
    @Query('q') q?: string,
    @Query('limit') limit?: string,
    @Query('rubro_id') rubroId?: string,
  ) {
    return this.comprasService.searchProveedores(user.empresa_id, q, Number(limit) || 20, rubroId || null, user.id);
  }

  @Get('config')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Configuración operativa de compras por empresa' })
  @ApiQuery({ name: 'sucursal_id', required: true })
  getConfig(@GetUser() user: LoginUserInfo, @Query('sucursal_id') sucursalId?: string) {
    if (!sucursalId) {
      throw new BadRequestException('sucursal_id es obligatorio');
    }
    return this.comprasService.getConfig(user.empresa_id, sucursalId);
  }

  @Get('config-moneda')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Config de decimales/redondeo por moneda para compras' })
  listConfigMoneda(@GetUser() user: LoginUserInfo) {
    return this.comprasService.listConfigMoneda(user.empresa_id);
  }

  @Put('config-moneda')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Crear/actualizar config de decimales/redondeo de una moneda' })
  upsertConfigMoneda(@GetUser() user: LoginUserInfo, @Body() dto: UpsertConfigComprasMonedaDto) {
    return this.comprasService.upsertConfigMoneda(user.empresa_id, dto);
  }

  @Delete('config-moneda/:monedaId')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Eliminar override (la moneda vuelve al fallback)' })
  deleteConfigMoneda(@GetUser() user: LoginUserInfo, @Param('monedaId') monedaId: string) {
    return this.comprasService.deleteConfigMoneda(user.empresa_id, monedaId);
  }

  @Get('ultimo-costo')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Último costo de compra para proveedor y producto' })
  @ApiQuery({ name: 'proveedor_id', required: true })
  @ApiQuery({ name: 'producto_id', required: true })
  getUltimoCostoProveedor(
    @GetUser() user: LoginUserInfo,
    @Query('proveedor_id') proveedorId?: string,
    @Query('producto_id') productoId?: string,
  ) {
    if (!proveedorId) throw new BadRequestException('proveedor_id es obligatorio');
    if (!productoId) throw new BadRequestException('producto_id es obligatorio');
    return this.comprasService.getUltimoCostoProveedor(user.empresa_id, proveedorId, productoId);
  }

  @Get('dashboard')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Resumen de compras para dashboard' })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'fecha_desde_anterior', required: false })
  @ApiQuery({ name: 'fecha_hasta_anterior', required: false })
  @ApiQuery({ name: 'moneda_id', required: false })
  @ApiQuery({ name: 'proveedor_id', required: false })
  @ApiQuery({ name: 'sucursal_id', required: false })
  @ApiQuery({ name: 'deposito_id', required: false })
  @ApiQuery({ name: 'producto_id', required: false })
  getDashboard(
    @GetUser() user: LoginUserInfo,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('fecha_desde_anterior') fecha_desde_anterior?: string,
    @Query('fecha_hasta_anterior') fecha_hasta_anterior?: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('proveedor_id') proveedor_id?: string,
    @Query('sucursal_id') sucursal_id?: string,
    @Query('deposito_id') deposito_id?: string,
    @Query('producto_id') producto_id?: string,
  ) {
    return this.comprasService.getDashboard(user.empresa_id, {
      fecha_desde,
      fecha_hasta,
      fecha_desde_anterior,
      fecha_hasta_anterior,
      moneda_id,
      proveedor_id,
      sucursal_id,
      deposito_id,
      producto_id,
      usuarioId: user.id,
    });
  }

  @Get('verificar-comprobante')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Verifica si un comprobante ya existe como compra o gasto (no bloquea, solo informa)' })
  @ApiQuery({ name: 'numero_factura', required: true })
  @ApiQuery({ name: 'timbrado', required: false })
  @ApiQuery({ name: 'establecimiento', required: false })
  @ApiQuery({ name: 'punto_expedicion', required: false })
  @ApiQuery({ name: 'excluir_id', required: false, description: 'ID del registro que se edita, para no marcarlo como duplicado de sí mismo' })
  async verificarComprobante(
    @GetUser() user: LoginUserInfo,
    @Query('numero_factura') numero_factura: string,
    @Query('timbrado') timbrado?: string,
    @Query('establecimiento') establecimiento?: string,
    @Query('punto_expedicion') punto_expedicion?: string,
    @Query('excluir_id') excluir_id?: string,
  ) {
    return this.comprasService.verificarComprobanteDuplicado(user.empresa_id, {
      numero_factura,
      timbrado,
      establecimiento,
      punto_expedicion,
      excluir_id,
    });
  }

  @Get('libro-iva-compras')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Libro IVA Compras - 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' })
  @ApiQuery({
    name: 'tipo_comprobante',
    required: false,
    enum: ['preimpresos', 'electronicos', 'todos'],
    description:
      'Qué comprobantes traer (default "preimpresos"). "electronicos" devuelve solo los que la ' +
      'DNIT ya tiene, para cruzar contra Marangatu; "todos" trae el período completo.',
  })
  @ApiQuery({
    name: 'solo_preimpresos',
    required: false,
    deprecated: true,
    description: 'Obsoleto, usar tipo_comprobante. "false" equivale a tipo_comprobante=todos.',
  })
  async getLibroIvaCompras(
    @GetUser() user: LoginUserInfo,
    @Query('mes') mes: string,
    @Query('anio') anio: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('tipo_comprobante') tipo_comprobante?: string,
    @Query('solo_preimpresos') solo_preimpresos?: string,
  ) {
    return this.comprasService.getLibroIvaCompras(
      user.empresa_id,
      Number(mes),
      Number(anio),
      moneda_id,
      tipoComprobanteLibro(tipo_comprobante, solo_preimpresos),
      user.id,
    );
  }

  @Get('libro-iva-compras/marangatu')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Libro IVA Compras - 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.)' })
  @ApiQuery({
    name: 'tipo_comprobante',
    required: false,
    enum: ['preimpresos', 'electronicos', 'todos'],
    description: 'Qué comprobantes exportar (default "preimpresos").',
  })
  @ApiQuery({
    name: 'solo_preimpresos',
    required: false,
    deprecated: true,
    description: 'Obsoleto, usar tipo_comprobante. "false" equivale a tipo_comprobante=todos.',
  })
  async getLibroIvaComprasMarangatu(
    @GetUser() user: LoginUserInfo,
    @Query('mes') mes: string,
    @Query('anio') anio: string,
    @Query('moneda_id') moneda_id?: string,
    @Query('secuencia') secuencia?: string,
    @Query('tipo_comprobante') tipo_comprobante?: string,
    @Query('solo_preimpresos') solo_preimpresos?: string,
  ) {
    return this.comprasService.getLibroIvaComprasMarangatu(
      user.empresa_id,
      Number(mes),
      Number(anio),
      moneda_id,
      secuencia || undefined,
      tipoComprobanteLibro(tipo_comprobante, solo_preimpresos),
      user.id,
    );
  }

  @Get(':id')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Detalle de compra' })
  findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.comprasService.findOne(id, user.empresa_id);
  }

  @Patch(':id')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Actualizar compra (edición completa)' })
  @Auditable('compra')
  @UseInterceptors(AuditInterceptor)
  update(@Param('id') id: string, @Body() dto: UpdateCompraDto, @GetUser() user: LoginUserInfo) {
    return this.comprasService.update(id, dto, user.empresa_id, user.id);
  }

  @Patch(':id/anular')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Anular compra y revertir impacto de stock/costos' })
  @Auditable('compra')
  @UseInterceptors(AuditInterceptor)
  anular(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.comprasService.anular(id, user.empresa_id, user.id);
  }

  @Post(':id/reintentar-contabilidad')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Reintentar integración contable de la compra' })
  reintentarContabilidad(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.comprasService.reintentarContabilidad(id, user.empresa_id);
  }
}
