import {
  Controller,
  Post,
  Get,
  Body,
  Param,
  ParseIntPipe,
  Query,
  Req,
  Res,
  UseGuards,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { Response } from 'express';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiSecurity, ApiBody, ApiParam } from '@nestjs/swagger';
import { ResponseService } from 'src/common/response-handling/response-handler';
import { handleControllerError } from 'src/common/utils/controller-response-handling';
import { RolesGuard } from 'src/common/guards/roles.guard';
import { Roles } from 'src/common/decorators/roles.decorator';
import { ROLE_VALUES } from 'src/common/constants/strings-constants';
import { CombinedAuthGuard } from 'src/auth/combined-auth.guard';
import { AuthenticatedRequest } from 'src/common/interfaces/authenticated-request.interface';
import { ZOOM_SWAGGER } from 'src/common/constants/zoom.constants';
import { ZoomGeneratedLinkService } from '../services/zoom-generated-link.service';
import { GenerateZoomGeneralLinksV1Dto } from '../dto/generate-zoom-general-links-v1.dto';
import { ListZoomGeneralLinksV1Dto } from '../dto/list-zoom-general-links-v1.dto';
import { ListZoomGeneralLinksByUserV1Dto } from '../dto/list-zoom-general-links-by-user-v1.dto';

/**
 * Bulk-generates Zoom registrant join links for people with no `ProgramRegistration` row of
 * their own — real staff users matched by role, and/or a caller-named placeholder batch. Scope
 * is `programId` (every Zoom-provisioned session of that program) XOR `sessionId` (one session
 * only), same convention as `POST online-session/registrations/bulk`. See
 * `ZoomGeneratedLinkService` for the generation logic. Admin-only: this hits the real Zoom API
 * and creates real registrants.
 */
@ApiTags(ZOOM_SWAGGER.TAG)
@Controller('v1/zoom/general-links')
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles(ROLE_VALUES.ADMIN, ROLE_VALUES.COORDINATOR, ROLE_VALUES.RELATIONAL_MANAGER)
@ApiBearerAuth('Authorization')
@ApiSecurity('userIdAuth')
@ApiSecurity('activeRoleAuth')
export class ZoomGeneralLinkController {
  constructor(
    private readonly linkService: ZoomGeneratedLinkService,
    private readonly responseService: ResponseService,
  ) {}

  @Post()
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: 'Bulk-generate Zoom registrant links for role-matched users and/or a placeholder batch, across a program or one session' })
  @ApiBody({ type: GenerateZoomGeneralLinksV1Dto })
  async generate(
    @Body() dto: GenerateZoomGeneralLinksV1Dto,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      const data = await this.linkService.generate(dto, req.user?.id ?? undefined);
      await this.responseService.success(res, 'Zoom general links generated', data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get()
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: 'List previously generated Zoom general links for a program or one session' })
  async list(@Query() query: ListZoomGeneralLinksV1Dto, @Res() res: Response) {
    try {
      const data = await this.linkService.list(
        { programId: query.programId, sessionId: query.sessionId },
        query.page,
        query.limit,
      );
      await this.responseService.success(res, 'Zoom general links fetched', data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get('user/:userId')
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: 'Fetch previously generated Zoom registrant links (join URL included) for one user — every program/session by default, optionally narrowed by programId and/or sessionId' })
  @ApiParam({ name: 'userId', type: Number })
  async listByUser(
    @Param('userId', ParseIntPipe) userId: number,
    @Query() query: ListZoomGeneralLinksByUserV1Dto,
    @Res() res: Response,
  ) {
    try {
      const data = await this.linkService.listByUser(userId, query.programId, query.sessionId);
      await this.responseService.success(res, 'Zoom general links fetched', data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }
}
