import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Req,
  UnauthorizedException,
  UseGuards,
} from '@nestjs/common';

import type { Request } from 'express';

import { Roles } from '@/casl/roles.decorator';
import { RolesGuard } from '@/casl/roles.guard';
import { JwtAuthGuard } from '@/modules/auth/jwt-auth.guard';

import { SaveProgressReportEvaluationsDto } from './dto/save-progress-report-evaluations.dto';
import { ProgressReportEvaluationsService } from './progress-report-evaluations.service';

type AuthenticatedRequest = Request & {
  user?: {
    id?: number | string;
    userId?: number | string;
    sub?: number | string;
  };
};

@UseGuards(JwtAuthGuard)
@Controller('progress-reports/assignments/:assignmentId/evaluations')
export class ProgressReportEvaluationsController {
  constructor(private readonly service: ProgressReportEvaluationsService) {}

  /**
   * GET
   * /progress-reports/assignments/:assignmentId/evaluations/form
   *
   * Returns the exact issues belonging to the Progress Report
   * assignment and the latest saved evaluation for each issue.
   */
  @Get('form')
  getEvaluationForm(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,

    @Req()
    request: AuthenticatedRequest,
  ) {
    return this.service.getEvaluationForm(
      assignmentId,
      this.getCurrentUserId(request),
    );
  }

  /**
   * GET
   * /progress-reports/assignments/:assignmentId/evaluations/submitted
   *
   * Admin/detail view of the latest PSWG submission.
   */
  @Get('submitted')
  getSubmittedEvaluationForm(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,
  ) {
    return this.service.getSubmittedEvaluationForm(assignmentId);
  }

  /**
   * PATCH
   * /progress-reports/assignments/:assignmentId/evaluations/submitted
   */
  @Patch('submitted')
  @UseGuards(RolesGuard)
  @Roles('admin')
  @HttpCode(HttpStatus.OK)
  updateSubmittedEvaluationForm(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,

    @Body()
    dto: SaveProgressReportEvaluationsDto,
  ) {
    return this.service.updateSubmittedEvaluationForm(assignmentId, dto);
  }

  /**
   * GET
   * /progress-reports/assignments/:assignmentId/evaluations
   *
   * Current authenticated user's saved evaluations.
   */
  @Get()
  findAll(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,

    @Req()
    request: AuthenticatedRequest,
  ) {
    return this.service.findAll(assignmentId, this.getCurrentUserId(request));
  }

  /**
   * POST
   * /progress-reports/assignments/:assignmentId/evaluations
   */
  @Post()
  @HttpCode(HttpStatus.OK)
  save(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,

    @Body()
    dto: SaveProgressReportEvaluationsDto,

    @Req()
    request: AuthenticatedRequest,
  ) {
    return this.service.save(assignmentId, this.getCurrentUserId(request), dto);
  }

  /**
   * DELETE
   * /progress-reports/assignments/:assignmentId/evaluations/:evaluationId
   */
  @Delete(':evaluationId')
  remove(
    @Param('assignmentId', ParseIntPipe)
    assignmentId: number,

    @Param('evaluationId', ParseIntPipe)
    evaluationId: number,

    @Req()
    request: AuthenticatedRequest,
  ) {
    return this.service.remove(
      assignmentId,
      evaluationId,
      this.getCurrentUserId(request),
    );
  }

  private getCurrentUserId(request: AuthenticatedRequest): number {
    const rawUserId =
      request.user?.id ?? request.user?.userId ?? request.user?.sub;

    const userId = Number(rawUserId);

    if (!Number.isInteger(userId) || userId <= 0) {
      throw new UnauthorizedException('Invalid authenticated user.');
    }

    return userId;
  }
}
