import { Op } from 'sequelize';
import { checkAccess } from '../utils/userUtils.js';
import TrainingGroup from '../models/TrainingGroup.js';
import MemberTrainingGroup from '../models/MemberTrainingGroup.js';
import Member from '../models/Member.js';
import ClubDisabledPresetGroup from '../models/ClubDisabledPresetGroup.js';
import HttpError from '../exceptions/HttpError.js';

class TrainingGroupService {
    // Vorgaben-Gruppen beim Vereins-Erstellen anlegen (idempotent - erstellt nur fehlende)
    async createPresetGroups(clubId) {
        const presetGroups = [
            { name: 'Anfänger', presetType: 'anfaenger', sortOrder: 1 },
            { name: 'Fortgeschrittene', presetType: 'fortgeschrittene', sortOrder: 2 },
            { name: 'Erwachsene', presetType: 'erwachsene', sortOrder: 3 },
            { name: 'Nachwuchs', presetType: 'nachwuchs', sortOrder: 4 },
            { name: 'Leistungsgruppe', presetType: 'leistungsgruppe', sortOrder: 5 },
        ];

        // Hole alle deaktivierten Preset-Gruppen für diesen Verein
        const disabledPresetGroups = await ClubDisabledPresetGroup.findAll({
            where: { clubId },
        });
        const disabledPresetTypes = new Set(disabledPresetGroups.map(d => d.presetType));

        const createdGroups = [];
        for (const preset of presetGroups) {
            // Überspringe deaktivierte Preset-Gruppen
            if (disabledPresetTypes.has(preset.presetType)) {
                continue;
            }

            // Prüfe, ob diese Preset-Gruppe bereits existiert
            const existing = await TrainingGroup.findOne({
                where: { 
                    clubId, 
                    isPreset: true, 
                    presetType: preset.presetType 
                },
            });
            
            if (!existing) {
                const group = await TrainingGroup.create({
                    clubId,
                    name: preset.name,
                    isPreset: true,
                    presetType: preset.presetType,
                    sortOrder: preset.sortOrder,
                });
                createdGroups.push(group);
            } else {
                createdGroups.push(existing);
            }
        }
        return createdGroups;
    }

    // Stelle sicher, dass alle Preset-Gruppen für einen Verein existieren
    async ensurePresetGroups(userToken, clubId) {
        await checkAccess(userToken, clubId);
        return await this.createPresetGroups(clubId);
    }

    // Aktiviere eine deaktivierte Preset-Gruppe wieder
    async enablePresetGroup(userToken, clubId, presetType) {
        await checkAccess(userToken, clubId);
        
        // Entferne die Deaktivierung
        await ClubDisabledPresetGroup.destroy({
            where: { clubId, presetType },
        });
        
        // Erstelle die Gruppe, falls sie nicht existiert
        const presetGroups = [
            { name: 'Anfänger', presetType: 'anfaenger', sortOrder: 1 },
            { name: 'Fortgeschrittene', presetType: 'fortgeschrittene', sortOrder: 2 },
            { name: 'Erwachsene', presetType: 'erwachsene', sortOrder: 3 },
            { name: 'Nachwuchs', presetType: 'nachwuchs', sortOrder: 4 },
            { name: 'Leistungsgruppe', presetType: 'leistungsgruppe', sortOrder: 5 },
        ];
        
        const preset = presetGroups.find(p => p.presetType === presetType);
        if (!preset) {
            throw new HttpError('Ungültiger Preset-Typ', 400);
        }
        
        const existing = await TrainingGroup.findOne({
            where: { 
                clubId, 
                isPreset: true, 
                presetType: presetType 
            },
        });
        
        if (!existing) {
            return await TrainingGroup.create({
                clubId,
                name: preset.name,
                isPreset: true,
                presetType: preset.presetType,
                sortOrder: preset.sortOrder,
            });
        }
        
        return existing;
    }

    async getTrainingGroups(userToken, clubId) {
        await checkAccess(userToken, clubId);
        
        // Stelle sicher, dass alle Preset-Gruppen existieren
        await this.ensurePresetGroups(userToken, clubId);
        
        const groups = await TrainingGroup.findAll({
            where: { clubId },
            order: [
                ['isPreset', 'DESC'], // Preset-Gruppen zuerst
                ['sortOrder', 'ASC'],
                ['name', 'ASC'],
            ],
            include: [
                {
                    model: Member,
                    as: 'members',
                    through: { attributes: [] }, // Keine Junction-Table-Attribute
                    attributes: ['id', 'firstName', 'lastName'],
                    required: false, // LEFT JOIN, damit auch Gruppen ohne Mitglieder zurückgegeben werden
                },
            ],
        });
        // Stelle sicher, dass es ein Array ist und dass jedes Gruppen-Objekt ein members-Array hat
        return groups.map(group => {
            const groupData = group.toJSON ? group.toJSON() : group;
            return {
                ...groupData,
                members: Array.isArray(groupData.members) ? groupData.members : []
            };
        });
    }

    async createTrainingGroup(userToken, clubId, name, sortOrder = 0) {
        await checkAccess(userToken, clubId);
        
        // Prüfe, ob bereits eine Gruppe mit diesem Namen existiert
        const existing = await TrainingGroup.findOne({
            where: { clubId, name },
        });
        if (existing) {
            throw new HttpError('Eine Gruppe mit diesem Namen existiert bereits', 409);
        }

        const group = await TrainingGroup.create({
            clubId,
            name,
            isPreset: false,
            presetType: null,
            sortOrder,
        });
        return group;
    }

    async updateTrainingGroup(userToken, clubId, groupId, body = {}) {
        await checkAccess(userToken, clubId);

        const { name, sortOrder, excludeFromQuickDiaryCreate } = body;

        const group = await TrainingGroup.findOne({
            where: { id: groupId, clubId },
        });
        if (!group) {
            throw new HttpError('Gruppe nicht gefunden', 404);
        }

        if (name !== undefined && name !== null) {
            // Preset-Gruppen können nicht umbenannt werden
            if (group.isPreset && name !== group.name) {
                throw new HttpError('Vorgaben-Gruppen können nicht umbenannt werden', 400);
            }

            if (name !== group.name) {
                const existing = await TrainingGroup.findOne({
                    where: { clubId, name, id: { [Op.ne]: groupId } },
                });
                if (existing) {
                    throw new HttpError('Eine Gruppe mit diesem Namen existiert bereits', 409);
                }
            }
            group.name = name;
        }

        if (sortOrder !== undefined && sortOrder !== null) {
            group.sortOrder = sortOrder;
        }

        if (excludeFromQuickDiaryCreate !== undefined) {
            group.excludeFromQuickDiaryCreate = Boolean(excludeFromQuickDiaryCreate);
        }

        await group.save();
        return group;
    }

    async deleteTrainingGroup(userToken, clubId, groupId) {
        await checkAccess(userToken, clubId);
        
        const group = await TrainingGroup.findOne({
            where: { id: groupId, clubId },
        });
        if (!group) {
            throw new HttpError('Gruppe nicht gefunden', 404);
        }

        // Wenn es eine Preset-Gruppe ist, markiere sie als deaktiviert statt sie zu löschen
        if (group.isPreset && group.presetType) {
            // Prüfe, ob bereits als deaktiviert markiert
            const existing = await ClubDisabledPresetGroup.findOne({
                where: { clubId, presetType: group.presetType },
            });
            
            if (!existing) {
                await ClubDisabledPresetGroup.create({
                    clubId,
                    presetType: group.presetType,
                });
            }
            
            // Lösche die Gruppe
            await group.destroy();
            return { success: true, message: 'Preset-Gruppe wurde deaktiviert und wird nicht automatisch wieder erstellt' };
        }

        await group.destroy();
        return { success: true };
    }

    async addMemberToGroup(userToken, clubId, groupId, memberId) {
        await checkAccess(userToken, clubId);
        
        // Prüfe, ob Gruppe existiert und zum Verein gehört
        const group = await TrainingGroup.findOne({
            where: { id: groupId, clubId },
        });
        if (!group) {
            throw new HttpError('Gruppe nicht gefunden', 404);
        }

        // Prüfe, ob Mitglied existiert und zum Verein gehört
        const member = await Member.findOne({
            where: { id: memberId, clubId },
        });
        if (!member) {
            throw new HttpError('Mitglied nicht gefunden', 404);
        }

        // Prüfe, ob Zuordnung bereits existiert
        const existing = await MemberTrainingGroup.findOne({
            where: { memberId, trainingGroupId: groupId },
        });
        if (existing) {
            throw new HttpError('Mitglied ist bereits in dieser Gruppe', 409);
        }

        const memberGroup = await MemberTrainingGroup.create({
            memberId,
            trainingGroupId: groupId,
        });
        return memberGroup;
    }

    async removeMemberFromGroup(userToken, clubId, groupId, memberId) {
        await checkAccess(userToken, clubId);
        
        // Prüfe, ob Gruppe existiert und zum Verein gehört
        const group = await TrainingGroup.findOne({
            where: { id: groupId, clubId },
        });
        if (!group) {
            throw new HttpError('Gruppe nicht gefunden', 404);
        }

        // Prüfe, ob Mitglied existiert und zum Verein gehört
        const member = await Member.findOne({
            where: { id: memberId, clubId },
        });
        if (!member) {
            throw new HttpError('Mitglied nicht gefunden', 404);
        }
        
        const memberGroup = await MemberTrainingGroup.findOne({
            where: { memberId, trainingGroupId: groupId },
        });
        if (!memberGroup) {
            throw new HttpError('Zuordnung nicht gefunden', 404);
        }

        await memberGroup.destroy();
        return { success: true };
    }

    async getMemberGroups(userToken, clubId, memberId) {
        await checkAccess(userToken, clubId);
        
        const member = await Member.findOne({
            where: { id: memberId, clubId },
        });
        if (!member) {
            throw new HttpError('Mitglied nicht gefunden', 404);
        }

        const groups = await TrainingGroup.findAll({
            where: { clubId },
            include: [
                {
                    model: Member,
                    as: 'members',
                    where: { id: memberId },
                    through: { attributes: [] },
                    required: true,
                },
            ],
            order: [
                ['isPreset', 'DESC'],
                ['sortOrder', 'ASC'],
                ['name', 'ASC'],
            ],
        });
        return groups;
    }
}

export default new TrainingGroupService();

