import {
  Controller,
  Post,
  Body,
  Req,
  Res,
  UseGuards,
  UsePipes,
  ValidationPipe,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiSecurity, ApiBody } 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 { ZoomFinalSessionConfirmService } from '../services/zoom-final-session-confirm.service';
import { ConfirmFinalSessionV1Dto } from '../dto/confirm-final-session-v1.dto';
import { ReinstateFinalSessionRegistrantV1Dto } from '../dto/reinstate-final-session-registrant-v1.dto';

/**
 * Attendance-driven cutoff for a program's final session: `POST /` unregisters
 * any seat-allocated registrant who missed one or more of the program's earlier
 * sessions from the final session's Zoom access; `POST /reinstate` re-adds one
 * registrant afterwards. Distinct from the registration activation toggle
 * (`online-session/registrations/:id/activation`) — see
 * `ZoomFinalSessionConfirmService` for why the two must not be merged.
 */
@ApiTags(ZOOM_SWAGGER.TAG)
@Controller('v1/zoom/final-session-confirm')
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles(ROLE_VALUES.ADMIN, ROLE_VALUES.COORDINATOR, ROLE_VALUES.RM)
@ApiBearerAuth('Authorization')
@ApiSecurity('userIdAuth')
@ApiSecurity('activeRoleAuth')
export class ZoomFinalSessionConfirmController {
  constructor(
    private readonly finalSessionConfirmService: ZoomFinalSessionConfirmService,
    private readonly responseService: ResponseService,
  ) {}

  /** Whether the caller holds the RM role — an RM only ever acts on their own contacts. */
  private isRelationalManager(req: AuthenticatedRequest): boolean {
    return (req.user?.roles ?? []).includes(ROLE_VALUES.RM) && !!req.user?.id;
  }

  @Post()
  @HttpCode(HttpStatus.OK)
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({
    summary:
      "Unregister every registrant who missed an earlier session of the program from the program's final session",
  })
  @ApiBody({ type: ConfirmFinalSessionV1Dto })
  async confirm(
    @Body() dto: ConfirmFinalSessionV1Dto,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      const rmContactId = this.isRelationalManager(req) ? req.user?.id : undefined;
      const data = await this.finalSessionConfirmService.confirmFinalSession(
        dto.programId,
        req.user?.id,
        rmContactId,
      );
      await this.responseService.success(res, 'Final session confirm run complete', data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Post('reinstate')
  @HttpCode(HttpStatus.OK)
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: 'Re-add a registrant who was unregistered from the final session' })
  @ApiBody({ type: ReinstateFinalSessionRegistrantV1Dto })
  async reinstate(
    @Body() dto: ReinstateFinalSessionRegistrantV1Dto,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      const rmContactId = this.isRelationalManager(req) ? req.user?.id : undefined;
      const data = await this.finalSessionConfirmService.reinstateForFinalSession(
        dto.registrationId,
        dto.reason,
        req.user?.id,
        rmContactId,
      );
      await this.responseService.success(res, 'Registrant reinstated for final session', data ?? undefined);
    } catch (error) {
      handleControllerError(res, error);
    }
  }
}
