import { BadRequestException, Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { GetUser } from 'src/auth/get-user.decorator';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { RequireModule, RequirePermission } from 'src/auth/decorators';
import { ModuleGuard } from 'src/auth/guards/module.guard';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { EcommercePedidosService } from './ecommerce-pedidos.service';

/**
 * Preparación compartida por ambas ramas (verificar, preparar, empaquetar,
 * dejar listo). No toca plata ni stock. Permiso: EC_PED_PEDIDO_PROCESAR.
 */
const ESTADOS_PREPARACION = [
  'en_verificacion',
  'verificado',
  'preparando',
  'empaquetado',
  'listo_retiro',
  'listo_despacho',
];

/** Rama delivery: despacho y entrega. Permiso propio: EC_PED_DESPACHO. */
const ESTADOS_DESPACHO = ['en_camino', 'entregado'];

/** Rama pickup: retiro en mostrador. Permiso propio: EC_PED_MOSTRADOR. */
const ESTADOS_RETIRO = ['retirado'];

@ApiTags('ecommerce-pedidos')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)
@RequireModule('ECOMMERCE')
@Controller({ path: 'ecommerce/pedidos', version: '1' })
export class EcommercePedidosController {
  constructor(private readonly service: EcommercePedidosService) {}

  @Get()
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_VER')
  @ApiOperation({ summary: 'Bandeja de pedidos ecommerce con conteo por estado (paginada)' })
  @ApiQuery({ name: 'estado', required: false })
  @ApiQuery({ name: 'q', required: false })
  @ApiQuery({ name: 'page', required: false })
  @ApiQuery({ name: 'limit', required: false })
  list(
    @GetUser() user: LoginUserInfo,
    @Query('estado') estado?: string,
    @Query('q') q?: string,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
  ) {
    return this.service.list(user.empresa_id, {
      estado,
      q,
      page: page ? Number(page) : undefined,
      limit: limit ? Number(limit) : undefined,
    });
  }

  @Get('export')
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_VER')
  @ApiOperation({ summary: 'Export de pedidos sin paginar (tope 2000) para descarga en Excel del panel' })
  @ApiQuery({ name: 'estado', required: false })
  @ApiQuery({ name: 'q', required: false })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  exportar(
    @GetUser() user: LoginUserInfo,
    @Query('estado') estado?: string,
    @Query('q') q?: string,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
  ) {
    return this.service.exportar(user.empresa_id, { estado, q, fecha_desde, fecha_hasta });
  }

  @Get(':id')
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_VER')
  @ApiOperation({ summary: 'Ficha operativa de un pedido ecommerce' })
  detail(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.detail(user.empresa_id, id);
  }

  /**
   * Sólo transiciones operativas. El motor resuelve los pasos habilitados y la
   * rama correcta según el tipo de entrega congelado en el checkout.
   *
   * Confirmar el pago y cancelar viven en endpoints propios porque mueven plata
   * y stock: si se pudieran disparar desde acá, quien tenga permiso de
   * "preparar" podría además dar por cobrado un pedido. Por eso este endpoint
   * rechaza explícitamente esos estados en vez de confiar sólo en el guard.
   */
  @Patch(':id/estado')
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_PROCESAR')
  @ApiOperation({ summary: 'Avanzar la preparación (verificar, preparar, empaquetar, dejar listo)' })
  changeEstado(
    @Param('id') id: string,
    @Body() body: { estado: string; notas?: string },
    @GetUser() user: LoginUserInfo,
  ) {
    if (!ESTADOS_PREPARACION.includes(body.estado)) {
      throw new BadRequestException(
        `Este endpoint sólo procesa estados de preparación (${ESTADOS_PREPARACION.join(', ')}). ` +
          'Despacho/entrega usan /despacho, retiro usa /retiro, y confirmar pago/cancelar sus endpoints.',
      );
    }
    return this.service.changeEstado(user.empresa_id, id, body.estado, body.notas, user.id);
  }

  /** Rama delivery. Segregado del mostrador: un despachante no atiende retiros. */
  @Patch(':id/despacho')
  @RequirePermission('ECOMMERCE', 'EC_PED_DESPACHO')
  @ApiOperation({ summary: 'Despacho de delivery: marcar en camino o entregado' })
  despacho(
    @Param('id') id: string,
    @Body() body: { estado: string; notas?: string },
    @GetUser() user: LoginUserInfo,
  ) {
    if (!ESTADOS_DESPACHO.includes(body.estado)) {
      throw new BadRequestException(
        `Este endpoint sólo procesa despacho de delivery (${ESTADOS_DESPACHO.join(', ')}).`,
      );
    }
    return this.service.changeEstado(user.empresa_id, id, body.estado, body.notas, user.id);
  }

  /** Rama pickup. Segregado del despacho: mostrador sólo confirma retiros. */
  @Patch(':id/retiro')
  @RequirePermission('ECOMMERCE', 'EC_PED_MOSTRADOR')
  @ApiOperation({ summary: 'Retiro en mostrador: confirmar que el cliente retiró el pedido' })
  retiro(
    @Param('id') id: string,
    @Body() body: { estado: string; notas?: string },
    @GetUser() user: LoginUserInfo,
  ) {
    if (!ESTADOS_RETIRO.includes(body.estado)) {
      throw new BadRequestException(
        `Este endpoint sólo procesa retiro en mostrador (${ESTADOS_RETIRO.join(', ')}).`,
      );
    }
    return this.service.changeEstado(user.empresa_id, id, body.estado, body.notas, user.id);
  }

  /** Congela el pedido con una incidencia (permiso de supervisor). Requiere motivo. */
  @Post(':id/incidencia')
  @RequirePermission('ECOMMERCE', 'EC_PED_INCIDENCIA')
  @ApiOperation({ summary: 'Marcar el pedido con una incidencia que lo saca del flujo normal' })
  incidencia(
    @Param('id') id: string,
    @Body() body: { notas?: string },
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.marcarIncidencia(user.empresa_id, id, body?.notas, user.id);
  }

  @Post(':id/confirmar-pago')
  @RequirePermission('ECOMMERCE', 'EC_PED_PAGO_CONFIRMAR')
  @ApiOperation({ summary: 'Confirmar el pago: crea el pedido ERP y reserva el stock' })
  confirmarPago(@Param('id') id: string, @Body() body: { notas?: string }, @GetUser() user: LoginUserInfo) {
    return this.service.changeEstado(user.empresa_id, id, 'pago_confirmado', body?.notas, user.id);
  }

  @Post(':id/cancelar')
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_CANCELAR')
  @ApiOperation({ summary: 'Cancelar el pedido: libera el stock reservado' })
  cancelar(@Param('id') id: string, @Body() body: { notas?: string }, @GetUser() user: LoginUserInfo) {
    return this.service.changeEstado(user.empresa_id, id, 'cancelado', body?.notas, user.id);
  }

  @Post(':id/crear-pedido-erp')
  @RequirePermission('ECOMMERCE', 'EC_PED_PEDIDO_ERP_CREAR')
  @ApiOperation({ summary: 'Crear/reintentar el pedido ERP + reserva de stock para esta sesión' })
  async crearPedidoErp(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    const pedidoId = await this.service.crearPedidoErp(user.empresa_id, id, user.id);
    return { ok: true, pedido_id: pedidoId };
  }
}
