import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { RequireModule } from 'src/auth/decorators/require-module.decorator';
import { RequirePermission } from 'src/auth/decorators/require-permission.decorator';
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 { InventarioFisicoService } from './inventario-fisico.service';
import { rubroDelRequest } from 'src/utils/rubro-context';

@ApiTags('Inventario Físico')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), ModuleGuard)
@RequireModule('INVENTARIO')
@Controller({ path: 'inventario-fisico', version: '1' })
export class InventarioFisicoController {
  constructor(private readonly service: InventarioFisicoService) {}

  // ── Sesiones ──────────────────────────────────────────────────────────────

  @Post('sesiones')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_CREAR')
  @ApiOperation({ summary: 'Crear sesión de inventario' })
  crearSesion(@Body('nombre') nombre: string, @GetUser() user: LoginUserInfo) {
    return this.service.crearSesion(user.empresa_id, nombre);
  }

  @Get('sesiones')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Listar sesiones de inventario' })
  listarSesiones(@GetUser() user: LoginUserInfo) {
    return this.service.listarSesiones(user.empresa_id, user.id);
  }

  @Patch('sesiones/:id/cerrar')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_CONFIRMAR')
  @ApiOperation({ summary: 'Cerrar sesión de inventario' })
  cerrarSesion(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.cerrarSesion(id, user.empresa_id);
  }

  @Get('sesiones/:id/progreso')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Ver progreso por zonas de una sesión' })
  progreso(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.progresoPorZona(id, user.empresa_id);
  }

  // ── Conteos ───────────────────────────────────────────────────────────────

  @Post('sesiones/:id/conteos')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_CREAR')
  @ApiOperation({ summary: 'Registrar o actualizar conteo de un producto' })
  registrarConteo(
    @Param('id') sesionId: string,
    @Body() body: { deposito_id: string; categoria_id?: string; producto_id: string; cantidad_contada: number },
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.registrarConteo(sesionId, user.empresa_id, {
      ...body,
      usuario_id: user.id,
    });
  }

  @Get('sesiones/:id/conteos')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Listar conteos de una sesión' })
  @ApiQuery({ name: 'depositoId', required: false })
  @ApiQuery({ name: 'categoriaId', required: false })
  listarConteos(
    @Param('id') sesionId: string,
    @GetUser() user: LoginUserInfo,
    @Query('depositoId') depositoId?: string,
    @Query('categoriaId') categoriaId?: string,
  ) {
    return this.service.listarConteos(sesionId, user.empresa_id, { depositoId, categoriaId });
  }

  @Delete('sesiones/:id/conteos')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_CONFIRMAR')
  @ApiOperation({ summary: 'Eliminar conteo de un producto (deshacer)' })
  @ApiQuery({ name: 'productoId', required: true })
  @ApiQuery({ name: 'depositoId', required: true })
  eliminarConteo(
    @Param('id') sesionId: string,
    @GetUser() user: LoginUserInfo,
    @Query('productoId') productoId: string,
    @Query('depositoId') depositoId: string,
  ) {
    return this.service.eliminarConteo(sesionId, user.empresa_id, productoId, depositoId);
  }

  // ── Zona ─────────────────────────────────────────────────────────────────

  @Post('sesiones/:id/zonas/cerrar')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_CONFIRMAR')
  @ApiOperation({ summary: 'Cerrar zona y aplicar ajuste de stock' })
  cerrarZona(
    @Param('id') sesionId: string,
    @Body() body: { deposito_id: string; categoria_id?: string; mantener_stock_no_contados?: boolean },
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.cerrarZona(
      sesionId,
      user.empresa_id,
      body.deposito_id,
      body.categoria_id ?? null,
      body.mantener_stock_no_contados ?? false,
      user.id,
    );
  }

  @Get('sesiones/:id/zonas-aplicadas')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Historial de zonas con ajuste aplicado en la sesión' })
  zonasAplicadas(@Param('id') sesionId: string, @GetUser() user: LoginUserInfo) {
    return this.service.zonasAplicadas(sesionId, user.empresa_id);
  }

  @Get('productos-zona')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Listar productos de una zona para conteo' })
  @ApiQuery({ name: 'depositoId', required: false })
  @ApiQuery({ name: 'sesionId', required: true })
  @ApiQuery({ name: 'categoriaId', required: false })
  @ApiQuery({ name: 'marcaId', required: false })
  @ApiQuery({ name: 'busqueda', required: false })
  @ApiQuery({ name: 'skip', required: false })
  @ApiQuery({ name: 'take', required: false })
  @ApiQuery({ name: 'filtro', required: false, enum: ['contados', 'pendientes'] })
  productosZona(
    @GetUser() user: LoginUserInfo,
    @Query('depositoId') depositoId?: string,
    @Query('sesionId') sesionId?: string,
    @Query('categoriaId') categoriaId?: string,
    @Query('marcaId') marcaId?: string,
    @Query('busqueda') busqueda?: string,
    @Query('skip') skip?: string,
    @Query('take') take?: string,
    @Query('filtro') filtro?: string,
  ) {
    return this.service.productosZona(
      user.empresa_id,
      depositoId,
      categoriaId ? categoriaId.split(',').filter(Boolean) : null,
      sesionId,
      busqueda,
      skip ? parseInt(skip) : 0,
      take ? parseInt(take) : 50,
      marcaId ? marcaId.split(',').filter(Boolean) : undefined,
      filtro === 'contados' || filtro === 'pendientes' ? filtro : undefined,
      // Rubro del selector del sidebar (header x-rubro-id), como en Productos.
      { usuarioId: user.id, rubroId: rubroDelRequest() },
    );
  }

  @Get('sesiones/:id/no-contados')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Productos no contados en una sesión de inventario' })
  @ApiQuery({ name: 'depositoId', required: false })
  @ApiQuery({ name: 'categoriaId', required: false, description: 'IDs separados por coma' })
  @ApiQuery({ name: 'busqueda', required: false })
  @ApiQuery({ name: 'skip', required: false })
  @ApiQuery({ name: 'take', required: false })
  productosNoContados(
    @Param('id') sesionId: string,
    @GetUser() user: LoginUserInfo,
    @Query('depositoId') depositoId?: string,
    @Query('categoriaId') categoriaId?: string,
    @Query('busqueda') busqueda?: string,
    @Query('skip') skip?: string,
    @Query('take') take?: string,
  ) {
    return this.service.productosNoContados(
      sesionId,
      user.empresa_id,
      depositoId,
      categoriaId ? categoriaId.split(',').filter(Boolean) : undefined,
      busqueda,
      skip ? parseInt(skip) : 0,
      take ? parseInt(take) : 50,
    );
  }

  // ── Planilla PDF data ─────────────────────────────────────────────────────

  @Get('planilla')
  @UseGuards(PermissionGuard)
  @RequirePermission('INVENTARIO', 'INV_CON_CONTEO_VER')
  @ApiOperation({ summary: 'Datos para planilla imprimible por zona' })
  @ApiQuery({ name: 'depositoId', required: true })
  @ApiQuery({ name: 'categoriaId', required: false })
  getPlanilla(
    @GetUser() user: LoginUserInfo,
    @Query('depositoId') depositoId: string,
    @Query('categoriaId') categoriaId?: string,
  ) {
    return this.service.getPlanillaData(user.empresa_id, depositoId, categoriaId ?? null);
  }
}
