import { Controller, Get, Param, Post, Query, UseGuards } from "@nestjs/common";
import {
  ApiBearerAuth,
  ApiOperation,
  ApiQuery,
  ApiResponse,
  ApiTags,
} from "@nestjs/swagger";
import { Provider, WebhookEventOutStatus } from "@prisma/client";
import { AdminUserGuard } from "../admin-auth/admin-user.guard";
import { ApiErrorResponse } from "../common/swagger/api-error.schema";
import { AdminEventsService } from "./admin-events.service";
import {
  EventInDto,
  EventInListDto,
  EventOutDto,
  EventOutListDto,
} from "./dto/event-out.dto";

@ApiTags("Admin · Events")
@ApiBearerAuth("adminUserAuth")
@ApiResponse({ status: 401, description: "Token admin faltante o inválido.", type: ApiErrorResponse })
@ApiResponse({ status: 429, description: "Rate limit excedido.", type: ApiErrorResponse })
@Controller("admin/merchants/:merchantId/events")
@UseGuards(AdminUserGuard)
export class AdminEventsController {
  constructor(private readonly service: AdminEventsService) {}

  @Get("outbound")
  @ApiOperation({
    operationId: "adminEventsListOutbound",
    summary: "Listar webhooks salientes del merchant",
  })
  @ApiQuery({ name: "limit", required: false, type: Number, example: 20 })
  @ApiQuery({ name: "cursor", required: false, type: String })
  @ApiQuery({ name: "status", required: false, enum: WebhookEventOutStatus })
  @ApiQuery({ name: "endpointId", required: false, type: String })
  @ApiResponse({ status: 200, type: EventOutListDto })
  listOutbound(
    @Param("merchantId") merchantId: string,
    @Query("limit") limit?: string,
    @Query("cursor") cursor?: string,
    @Query("status") status?: WebhookEventOutStatus,
    @Query("endpointId") endpointId?: string,
  ) {
    return this.service.listOutbound({
      merchantId,
      limit: limit ? Number(limit) : undefined,
      cursor,
      status,
      endpointId,
    });
  }

  @Get("outbound/:eventId")
  @ApiOperation({ operationId: "adminEventsRetrieveOutbound", summary: "Detalle de webhook saliente" })
  @ApiResponse({ status: 200, type: EventOutDto })
  @ApiResponse({ status: 404, description: "Event no encontrado.", type: ApiErrorResponse })
  async retrieveOutbound(
    @Param("merchantId") merchantId: string,
    @Param("eventId") eventId: string,
  ) {
    const result = await this.service.listOutbound({ merchantId, limit: 1, cursor: undefined });
    return result.data.find((e) => e.id === eventId) ?? { notFound: true };
  }

  @Post("outbound/:eventId/retry")
  @ApiOperation({
    operationId: "adminEventsRetryOutbound",
    summary: "Forzar reintento manual de un webhook saliente",
    description: "Re-encola el evento en estado `pending`. Disponible para events `pending`, `failed` o `dead`.",
  })
  @ApiResponse({ status: 201, description: "Reencolado." })
  @ApiResponse({ status: 400, description: "Event ya delivered.", type: ApiErrorResponse })
  @ApiResponse({ status: 404, description: "Event no encontrado.", type: ApiErrorResponse })
  retryOutbound(
    @Param("merchantId") merchantId: string,
    @Param("eventId") eventId: string,
  ) {
    return this.service.retryOutbound(merchantId, eventId);
  }

  @Get("inbound")
  @ApiOperation({
    operationId: "adminEventsListInbound",
    summary: "Listar webhooks entrantes (de providers) asociados al merchant",
  })
  @ApiQuery({ name: "limit", required: false, type: Number, example: 20 })
  @ApiQuery({ name: "cursor", required: false, type: String })
  @ApiQuery({ name: "provider", required: false, enum: Provider })
  @ApiQuery({ name: "processed", required: false, type: Boolean })
  @ApiResponse({ status: 200, type: EventInListDto })
  listInbound(
    @Param("merchantId") merchantId: string,
    @Query("limit") limit?: string,
    @Query("cursor") cursor?: string,
    @Query("provider") provider?: Provider,
    @Query("processed") processed?: string,
  ) {
    return this.service.listInbound({
      merchantId,
      limit: limit ? Number(limit) : undefined,
      cursor,
      provider,
      processed: processed === undefined ? undefined : processed === "true",
    });
  }
}
