import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Request,
  ParseIntPipe,
  ForbiddenException,
} from '@nestjs/common';
import { GradesService } from './grades.service';
import { CreateGradeDto, UpdateGradeDto } from './dto';
import { JwtAuthGuard, RolesGuard } from '../auth/guards';
import { Roles } from '../auth/guards/roles.guard';

@Controller('grades')
@UseGuards(JwtAuthGuard, RolesGuard)
export class GradesController {
  constructor(private readonly gradesService: GradesService) {}

  // Lehrer: Note erstellen
  @Post()
  @Roles(['Lehrer'])
  async createGrade(@Body() createGradeDto: CreateGradeDto) {
    return this.gradesService.createGrade(createGradeDto);
  }

  // Alle Noten für einen Stundenplan-Eintrag und Woche abrufen
  // Lehrer: Alle Noten, Schüler: Nur eigene Noten
  @Get('timetable/:timetableEntryId')
  async getGradesByTimetableEntry(
    @Param('timetableEntryId', ParseIntPipe) timetableEntryId: number,
    @Query('weekNumber', ParseIntPipe) weekNumber: number,
    @Query('year', ParseIntPipe) year: number,
    @Request() req,
  ) {
    const user = req.user;

    if (user.role === 'Lehrer') {
      // Lehrer können alle Noten für diesen Stundenplan-Eintrag und Woche sehen
      return this.gradesService.getGradesByTimetableEntry(timetableEntryId, weekNumber, year);
    } else {
      // Schüler können nur ihre eigenen Noten sehen
      return this.gradesService.getStudentGradesByTimetableEntry(
        user.id,
        timetableEntryId,
        weekNumber,
        year,
      );
    }
  }

  // Schüler: Alle eigenen Noten abrufen
  // Lehrer: Alle Noten abrufen (optional mit Filter)
  @Get()
  async getGrades(@Request() req, @Query() query: any) {
    const user = req.user;

    if (user.role === 'Lehrer') {
      // Lehrer können alle Noten abrufen (optional mit Filter)
      const filters: any = {};
      if (query.studentId) filters.studentId = parseInt(query.studentId);
      if (query.timetableEntryId) filters.timetableEntryId = parseInt(query.timetableEntryId);
      if (query.teacherId) filters.teacherId = query.teacherId;

      return this.gradesService.getAllGrades(filters);
    } else {
      // Schüler können nur ihre eigenen Noten abrufen
      return this.gradesService.getStudentGrades(user.id);
    }
  }

  // Schüler: Durchschnittsnote für ein Fach
  @Get('average/:timetableEntryId')
  async getAverageGrade(
    @Param('timetableEntryId', ParseIntPipe) timetableEntryId: number,
    @Request() req,
  ) {
    const user = req.user;

    // Nur Schüler können ihre eigene Durchschnittsnote abrufen
    if (user.role !== 'Student') {
      throw new ForbiddenException('Nur Schüler können Durchschnittsnoten abrufen');
    }

    return this.gradesService.calculateAverageForSubject(user.id, timetableEntryId);
  }

  // Schüler: Übersicht über alle Fächer
  @Get('overview')
  async getStudentOverview(@Request() req) {
    const user = req.user;

    // Nur Schüler können ihre Übersicht abrufen
    if (user.role !== 'Student') {
      throw new ForbiddenException('Nur Schüler können ihre Übersicht abrufen');
    }

    return this.gradesService.getStudentOverview(user.id);
  }

  // Lehrer: Komplette Notenübersicht für alle Fächer
  @Get('teacher/overview')
  @Roles(['Lehrer'])
  async getTeacherGradesOverview() {
    return this.gradesService.getTeacherGradesOverview();
  }

  // Lehrer: Detaillierte Notenansicht für ein spezifisches Fach (einzelner Stundenplan-Eintrag)
  @Get('subject/:timetableEntryId')
  @Roles(['Lehrer'])
  async getSubjectGradeDetails(
    @Param('timetableEntryId', ParseIntPipe) timetableEntryId: number,
  ) {
    return this.gradesService.getSubjectGradeDetails(timetableEntryId);
  }

  // Lehrer: Detaillierte Notenansicht für alle Stundenplan-Einträge mit gleichem Fachnamen
  @Get('subject-by-name/:subjectName')
  @Roles(['Lehrer'])
  async getSubjectGradeDetailsByName(
    @Param('subjectName') subjectName: string,
  ) {
    return this.gradesService.getSubjectGradeDetailsByName(subjectName);
  }

  // Lehrer: Note aktualisieren
  @Put(':id')
  @Roles(['Lehrer'])
  async updateGrade(
    @Param('id', ParseIntPipe) id: number,
    @Body() updateGradeDto: UpdateGradeDto,
  ) {
    return this.gradesService.updateGrade(id, updateGradeDto);
  }

  // Lehrer: Note löschen
  @Delete(':id')
  @Roles(['Lehrer'])
  async deleteGrade(@Param('id', ParseIntPipe) id: number) {
    return this.gradesService.deleteGrade(id);
  }
}
