import {
  Controller,
  Get,
  Post,
  Patch,
  Param,
  Query,
  Body,
  Req,
  Res,
  ParseIntPipe,
  UseGuards,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { Response } from 'express';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiSecurity, 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 { ZoomAnalyticsFacadeService } from 'src/zoom/services/zoom-analytics-facade.service';
import { AnalyticsAttendeeQueryDto } from '../dto/analytics-attendee-query.dto';
import { MarkAttendanceDto } from '../dto/mark-attendance.dto';
import { ANALYTICS_SWAGGER, ANALYTICS_RESPONSE } from '../constants/analytics.constants';

/**
 * Frontend-facing API. Owns zero database access — every read/write happens
 * inside the Zoom module via ZoomAnalyticsFacadeService, which resolves the
 * config-driven resource-type provider internally. This controller never
 * touches ZoomAnalyticsProviderRegistry or the providers directly.
 */
@ApiTags(ANALYTICS_SWAGGER.TAG)
@Controller('analytics/sessions')
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles('admin', 'shoba', 'relational_manager')
@ApiBearerAuth('Authorization')
@ApiSecurity('userIdAuth')
@ApiSecurity('activeRoleAuth')
export class AnalyticsController {
  constructor(
    private readonly facade: ZoomAnalyticsFacadeService,
    private readonly responseService: ResponseService,
  ) {}

  @Get(':sessionId/kpis')
  @Roles('admin', ROLE_VALUES.RELATIONAL_MANAGER, ROLE_VALUES.COORDINATOR)
  @ApiOperation({ summary: ANALYTICS_SWAGGER.GET_KPIS })
  @ApiParam({ name: 'sessionId', type: Number })
  async getKpis(
    @Param('sessionId', ParseIntPipe) sessionId: number,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      const data = await this.facade.getKpis(sessionId, req.user?.roles ?? [], req.user?.id ?? null);
      await this.responseService.success(res, ANALYTICS_RESPONSE.KPIS_FETCHED, data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get(':sessionId/live')
  @Roles('admin', ROLE_VALUES.RELATIONAL_MANAGER, ROLE_VALUES.COORDINATOR)
  @ApiOperation({ summary: ANALYTICS_SWAGGER.GET_LIVE })
  @ApiParam({ name: 'sessionId', type: Number })
  async getLive(@Param('sessionId', ParseIntPipe) sessionId: number, @Res() res: Response) {
    try {
      const data = await this.facade.getLiveStatus(sessionId);
      await this.responseService.success(res, ANALYTICS_RESPONSE.LIVE_FETCHED, data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get(':sessionId/attendees')
  @Roles('admin', ROLE_VALUES.RELATIONAL_MANAGER, ROLE_VALUES.COORDINATOR)
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: ANALYTICS_SWAGGER.GET_ATTENDEES })
  @ApiParam({ name: 'sessionId', type: Number })
  async getAttendees(
    @Param('sessionId', ParseIntPipe) sessionId: number,
    @Query() query: AnalyticsAttendeeQueryDto,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      const data = await this.facade.getAttendeeTable(
        sessionId,
        query,
        req.user?.roles ?? [],
        req.user?.id ?? null,
      );
      await this.responseService.success(res, ANALYTICS_RESPONSE.ATTENDEES_FETCHED, data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get(':sessionId/dashboard')
  @ApiOperation({ summary: ANALYTICS_SWAGGER.GET_DASHBOARD })
  @ApiParam({ name: 'sessionId', type: Number })
  async getDashboard(@Param('sessionId', ParseIntPipe) sessionId: number, @Res() res: Response) {
    try {
      const data = await this.facade.getDashboard(sessionId);
      await this.responseService.success(res, ANALYTICS_RESPONSE.DASHBOARD_FETCHED, data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Get(':sessionId/follow-ups')
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: ANALYTICS_SWAGGER.GET_FOLLOW_UPS })
  @ApiParam({ name: 'sessionId', type: Number })
  async getFollowUps(
    @Param('sessionId', ParseIntPipe) sessionId: number,
    @Query() query: AnalyticsAttendeeQueryDto,
    @Res() res: Response,
  ) {
    try {
      const data = await this.facade.getFollowUps(sessionId, query);
      await this.responseService.success(res, ANALYTICS_RESPONSE.FOLLOW_UPS_FETCHED, data);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Post(':sessionId/reconcile')
  @Roles('admin', ROLE_VALUES.RELATIONAL_MANAGER, ROLE_VALUES.COORDINATOR)
  @ApiOperation({ summary: ANALYTICS_SWAGGER.RECONCILE })
  @ApiParam({ name: 'sessionId', type: Number })
  async reconcile(@Param('sessionId', ParseIntPipe) sessionId: number, @Res() res: Response) {
    try {
      await this.facade.reconcile(sessionId);
      await this.responseService.success(res, ANALYTICS_RESPONSE.RECONCILED);
    } catch (error) {
      handleControllerError(res, error);
    }
  }

  @Patch(':sessionId/attendees/:attendeeId/attendance')
  @Roles('admin', ROLE_VALUES.RELATIONAL_MANAGER, ROLE_VALUES.COORDINATOR)
  @UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
  @ApiOperation({ summary: ANALYTICS_SWAGGER.MARK_ATTENDANCE })
  @ApiParam({ name: 'sessionId', type: Number })
  @ApiParam({ name: 'attendeeId', type: Number })
  async markAttendance(
    @Param('sessionId', ParseIntPipe) sessionId: number,
    @Param('attendeeId', ParseIntPipe) attendeeId: number,
    @Body() dto: MarkAttendanceDto,
    @Req() req: AuthenticatedRequest,
    @Res() res: Response,
  ) {
    try {
      await this.facade.markAttendance(
        sessionId,
        attendeeId,
        dto.source,
        dto.attended,
        req.user?.id ?? null,
        req.user?.roles ?? [],
      );
      await this.responseService.success(res, ANALYTICS_RESPONSE.ATTENDANCE_MARKED);
    } catch (error) {
      handleControllerError(res, error);
    }
  }
}
