import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateTimetableEntryDto, UpdateTimetableEntryDto } from './dto';

@Injectable()
export class TimetableService {
  constructor(private prisma: PrismaService) {}

  // Alle Stundenplan-Einträge für eine bestimmte Woche abrufen
  async getTimetable(weekNumber?: number, year?: number) {
    const currentDate = new Date();
    const targetWeek = weekNumber || this.getWeekNumber(currentDate);
    const targetYear = year || currentDate.getFullYear();

    return this.prisma.timetableEntry.findMany({
      where: {
        OR: [
          // Wiederkehrende Einträge (für alle Wochen)
          { isRecurring: true },
          // Spezifische Einträge für diese Woche
          {
            AND: [
              { weekNumber: targetWeek },
              { year: targetYear },
              { isRecurring: false },
            ],
          },
        ],
      },
      include: {
        subject: true, // Subject-Details laden
        teacher: { // Lehrer-Details laden
          select: {
            id: true,
            username: true,
            email: true,
          },
        },
        room: true, // Raum-Details laden
      },
      orderBy: [{ dayOfWeek: 'asc' }, { startTime: 'asc' }],
    });
  }

  // Kalenderwoche berechnen (ISO 8601)
  private getWeekNumber(date: Date): number {
    const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
  }

  // Einen neuen Stundenplan-Eintrag erstellen (nur für Lehrer)
  async createEntry(dto: CreateTimetableEntryDto) {
    let subjectId = dto.subjectId;
    if (!subjectId && dto.subjectName) {
      // Find or create subject
      const subject = await this.prisma.subject.upsert({
        where: { name: dto.subjectName },
        update: {},
        create: { name: dto.subjectName },
      });
      subjectId = subject.id;
    }

    if (!subjectId) {
      throw new Error('Subject ID or Name must be provided');
    }

    let roomId = dto.roomId;
    if (!roomId && dto.roomNumber) {
        // Find or create room
        const room = await this.prisma.room.upsert({
            where: { number: dto.roomNumber },
            update: {},
            create: { number: dto.roomNumber },
        });
        roomId = room.id;
    }

    return this.prisma.timetableEntry.create({
      data: {
        dayOfWeek: dto.dayOfWeek,
        startTime: dto.startTime,
        endTime: dto.endTime,
        subjectId: subjectId,
        teacherId: dto.teacherId,
        roomId: roomId,
        weekNumber: dto.weekNumber,
        year: dto.year,
        isRecurring: dto.isRecurring ?? true, // Standard: wiederkehrend
        allowStudentUploads: dto.allowStudentUploads ?? false,
      },
      include: {
        subject: true,
        teacher: {
          select: {
            id: true,
            username: true,
            email: true,
          },
        },
        room: true,
      },
    });
  }

  // Einen Stundenplan-Eintrag aktualisieren (nur für Lehrer)
  async updateEntry(entryId: number, dto: UpdateTimetableEntryDto) {
    // Prüfen, ob der Eintrag existiert
    const entry = await this.prisma.timetableEntry.findUnique({
      where: { id: entryId },
    });

    if (!entry) {
      throw new NotFoundException('Stundenplan-Eintrag nicht gefunden');
    }

    let subjectId = dto.subjectId;
    if (!subjectId && dto.subjectName) {
      const subject = await this.prisma.subject.upsert({
        where: { name: dto.subjectName },
        update: {},
        create: { name: dto.subjectName },
      });
      subjectId = subject.id;
    }

    let roomId = dto.roomId;
    if (!roomId && dto.roomNumber) {
        const room = await this.prisma.room.upsert({
            where: { number: dto.roomNumber },
            update: {},
            create: { number: dto.roomNumber },
        });
        roomId = room.id;
    }

    const data: any = { ...dto };
    if (subjectId) data.subjectId = subjectId;
    if (roomId) data.roomId = roomId;
    delete data.subjectName;
    delete data.roomNumber;

    return this.prisma.timetableEntry.update({
      where: { id: entryId },
      data: data,
      include: {
        subject: true,
        teacher: {
          select: {
            id: true,
            username: true,
            email: true,
          },
        },
        room: true,
      },
    });
  }

  // Einen Stundenplan-Eintrag löschen (nur für Lehrer)
  async deleteEntry(entryId: number) {
    // Prüfen, ob der Eintrag existiert
    const entry = await this.prisma.timetableEntry.findUnique({
      where: { id: entryId },
    });

    if (!entry) {
      throw new NotFoundException('Stundenplan-Eintrag nicht gefunden');
    }

    await this.prisma.timetableEntry.delete({
      where: { id: entryId },
    });

    return { message: 'Stundenplan-Eintrag erfolgreich gelöscht' };
  }
}
