import DiaryDate from '../models/DiaryDates.js';
import DiaryDateActivity from '../models/DiaryDateActivity.js';
import Club from '../models/Club.js';
import DiaryNote from '../models/DiaryNote.js';
import { DiaryTag } from '../models/DiaryTag.js';
import DiaryDateTag from '../models/DiaryDateTag.js';
import { checkAccess } from '../utils/userUtils.js';
import HttpError from '../exceptions/HttpError.js';

import { devLog } from '../utils/logger.js';
class DiaryService {
    async getDatesForClub(userToken, clubId) {
        await checkAccess(userToken, clubId);
        const club = await Club.findByPk(clubId);
        if (!club) {
            throw new HttpError('Club not found', 404);
        }
        const dates = await DiaryDate.findAll({
            where: { clubId },
            include: [
                { model: DiaryNote, as: 'diaryNotes' },  // Der Alias für DiaryNote ist korrekt
                { model: DiaryTag, as: 'diaryTags' },    // Hier muss der Alias auf 'diaryTags' geändert werden
            ],
            order: [['date', 'DESC'], ['trainingStart', 'ASC']]
        });
        return dates;
    }

    async createDateForClub(userToken, clubId, date, trainingStart, trainingEnd, excludeFromBilling = false) {
        await checkAccess(userToken, clubId);
        const club = await Club.findByPk(clubId);
        if (!club) {
            throw new HttpError('Club not found', 404);
        }
        const parsedDate = new Date(date);
        if (isNaN(parsedDate.getTime())) {
            throw new HttpError('Invalid date format', 400);
        }
        if (trainingStart && trainingEnd && trainingStart >= trainingEnd) {
            throw new HttpError('Training start time must be before training end time', 400);
        }
        const newDate = await DiaryDate.create({
            date: parsedDate,
            clubId,
            trainingStart: trainingStart || null,
            trainingEnd: trainingEnd || null,
            excludeFromBilling: Boolean(excludeFromBilling),
        });

        return newDate;
    }

    async updateTrainingTimes(userToken, clubId, dateId, trainingStart, trainingEnd, excludeFromBilling) {
        await checkAccess(userToken, clubId);
        const diaryDate = await DiaryDate.findOne({ where: { clubId, id: dateId } });
        if (!diaryDate) {
            throw new HttpError('Diary entry not found', 404);
        }
        if (trainingStart && trainingEnd && trainingStart >= trainingEnd) {
            throw new HttpError('Training start time must be before training end time', 400);
        }
        diaryDate.trainingStart = trainingStart || null;
        diaryDate.trainingEnd = trainingEnd || null;
        if (excludeFromBilling !== undefined) {
            diaryDate.excludeFromBilling = Boolean(excludeFromBilling);
        }
        await diaryDate.save();
        return diaryDate;
    }

    async addNoteToDate(userToken, diaryDateId, content) {
        await checkAccess(userToken, diaryDateId);
        await DiaryNote.create({ diaryDateId, content });
        return await DiaryNote.findAll({ where: { diaryDateId }, order: [['createdAt', 'DESC']] });
    }

    async deleteNoteFromDate(userToken, noteId) {
        const note = await DiaryNote.findByPk(noteId);
        if (!note) {
            throw new HttpError('Note not found', 404);
        }
        await checkAccess(userToken, note.diaryDateId);
        await note.destroy();
        return await DiaryNote.findAll({ where: { diaryDateId: note.diaryDateId }, order: [['createdAt', 'DESC']] });
    }

    async addTagToDate(userToken, diaryDateId, tagName) {
        await checkAccess(userToken, diaryDateId);
        let tag = await DiaryTag.findOne({ where: { name: tagName } });
        if (!tag) {
            tag = await DiaryTag.create({ name: tagName });
        }
        const diaryDate = await DiaryDate.findByPk(diaryDateId);
        await diaryDate.addDiaryTag(tag);
        return await diaryDate.getDiaryTags();
    }

    async addTagToDiaryDate(userToken, clubId, diaryDateId, tagId) {
        checkAccess(userToken, clubId);
        const diaryDate = await DiaryDate.findByPk(diaryDateId);
        if (!diaryDate) {
            throw new HttpError('DiaryDate not found', 404);
        }
        const existingEntry = await DiaryDateTag.findOne({
            where: { diaryDateId, tagId }
        });
        if (existingEntry) {
            return;
        }
        const tag = await DiaryTag.findByPk(tagId);  
        if (!tag) {
            throw new HttpError('Tag not found', 404);
        }
        await DiaryDateTag.create({
            diaryDateId,
            tagId
        });
        const tags = await DiaryDateTag.findAll({ where: {
            diaryDateId: diaryDateId },
            include: {
                model: DiaryTag,
                as: 'tag'
            }
        });  
        devLog(tags);
        return tags.map(tag => tag.tag);
    }

    async getDiaryNotesForDateAndMember(diaryDateId, memberId) {
        return await DiaryNote.findAll({
            where: { diaryDateId, memberId },
            order: [['createdAt', 'DESC']]
        });
    }

    async removeTagFromDiaryDate(userToken, clubId, tagId) {
        await checkAccess(userToken, clubId);
        await DiaryDateTag.destroy({ where: { tagId } });
    }

    async removeDateForClub(userToken, clubId, dateId) {
        await checkAccess(userToken, clubId);
        const diaryDate = await DiaryDate.findOne({ where: { id: dateId, clubId } });
        if (!diaryDate) {
            throw new HttpError('Diary entry not found', 404);
        }
        const activityCount = await DiaryDateActivity.count({ where: { diaryDateId: dateId } });
        if (activityCount > 0) {
            throw new HttpError('Cannot delete date with activities', 409);
        }
        await diaryDate.destroy();
        return { ok: true };
    }
}

export default new DiaryService();
