import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiOperation,
  ApiParam,
  ApiTags,
} from '@nestjs/swagger';
import { AppPermission } from '@aechr/shared';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import { Permissions as PermissionsDecorator } from '../../common/decorators/permissions.decorator';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import type { JwtAuthUser } from '../../common/interfaces/jwt-auth-user.interface';
import { ApiJwtErrorResponses } from '../../common/swagger/api-error-responses.decorator';
import {
  ApiEnvelopeOkResponse,
  ApiPaginatedEnvelopeOkResponse,
} from '../../common/swagger/api-success-responses.decorator';
import {
  AssignmentFormResponseDto,
  SubmissionResponseDto,
} from '../../common/swagger/response-models.dto';
import { SaveSubmissionDto } from './dto/save-submission.dto';
import { SubmissionQueryDto } from './dto/submission-query.dto';
import { SubmissionsService } from './submissions.service';

@ApiTags('Submissions')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('submissions')
export class SubmissionsController {
  constructor(private readonly submissionsService: SubmissionsService) {}

  @Get('me/:assignmentId')
  @ApiOperation({ summary: 'Get assignment form for the current user' })
  @ApiParam({ name: 'assignmentId', description: 'Assignment identifier' })
  @ApiEnvelopeOkResponse(
    AssignmentFormResponseDto,
    'Assignment form payload including questions and existing answers',
  )
  @ApiJwtErrorResponses({ notFound: 'Assignment was not found or is not available to the user' })
  getAssignmentForm(@Param('assignmentId') assignmentId: string, @CurrentUser() user: JwtAuthUser) {
    return this.submissionsService.getAssignmentForm(assignmentId, user);
  }

  @Post(':assignmentId/save-draft')
  @ApiOperation({ summary: 'Save submission draft' })
  @ApiParam({ name: 'assignmentId', description: 'Assignment identifier' })
  @ApiEnvelopeOkResponse(SubmissionResponseDto, 'Draft submission saved successfully')
  @ApiJwtErrorResponses({ notFound: 'Assignment was not found or is not available to the user' })
  saveDraft(
    @Param('assignmentId') assignmentId: string,
    @Body() body: SaveSubmissionDto,
    @CurrentUser() user: JwtAuthUser,
  ) {
    return this.submissionsService.saveDraft(assignmentId, body, user);
  }

  @Post(':assignmentId/submit')
  @ApiOperation({ summary: 'Submit final assessment answers' })
  @ApiParam({ name: 'assignmentId', description: 'Assignment identifier' })
  @ApiEnvelopeOkResponse(SubmissionResponseDto, 'Submission completed successfully')
  @ApiJwtErrorResponses({ notFound: 'Assignment was not found or is not available to the user' })
  submit(
    @Param('assignmentId') assignmentId: string,
    @Body() body: SaveSubmissionDto,
    @CurrentUser() user: JwtAuthUser,
  ) {
    return this.submissionsService.submit(assignmentId, body, user);
  }

  @Get(':id')
  @PermissionsDecorator(AppPermission.ASSIGNMENTS_READ)
  @ApiOperation({ summary: 'Get submission detail' })
  @ApiParam({ name: 'id', description: 'Submission identifier' })
  @ApiEnvelopeOkResponse(SubmissionResponseDto, 'Submission detail')
  @ApiJwtErrorResponses({ notFound: 'Submission was not found' })
  findOne(@Param('id') id: string) {
    return this.submissionsService.findOne(id);
  }

  @Get()
  @PermissionsDecorator(AppPermission.ASSIGNMENTS_READ)
  @ApiOperation({ summary: 'List submissions' })
  @ApiPaginatedEnvelopeOkResponse(SubmissionResponseDto, 'Paginated submission list')
  @ApiJwtErrorResponses()
  list(@Query() query: SubmissionQueryDto) {
    return this.submissionsService.list(query);
  }
}
