import Club from '../models/Club.js';
import UserClub from '../models/UserClub.js';
import User from '../models/User.js';
import Member from '../models/Member.js';
import { Op, fn, where, col } from 'sequelize';
import { checkAccess } from '../utils/userUtils.js';
import permissionService from './permissionService.js';
import trainingGroupService from './trainingGroupService.js';

class ClubService {
    async getAllClubs() { 
        return await Club.findAll();
    }

    async findClubByName(clubName) {
        return await Club.findOne({
            where: where(fn('LOWER', col('name')), 'LIKE', `%${clubName.toLowerCase()}%`)
        });
    }

    async createClub(clubName) {
        const club = await Club.create({ name: clubName });
        // Erstelle automatisch die Vorgaben-Gruppen
        await trainingGroupService.createPresetGroups(club.id);
        return club;
    }

    async addUserToClub(userId, clubId, isOwner = false) {
        const userClub = await UserClub.create({ 
            userId: userId, 
            clubId: clubId, 
            approved: true,
            isOwner: isOwner,
            role: isOwner ? 'admin' : 'member'
        });
        return userClub;
    }

    async getUserClubAccess(userId, clubId) {
        return await UserClub.findAll({
            where: {
                userId: userId,
                clubId: clubId,
            }
        });
    }

    async findClubById(clubId) {
        return await Club.findByPk(clubId, {
            include: [
                {
                    model: Member,
                    as: 'members',
                    order: [
                        ['lastName', 'ASC'],  // Sortiere nach Nachname aufsteigend
                        ['firstName', 'ASC']  // Sortiere nach Vorname aufsteigend
                    ],
                },
                {
                    model: User,
                    as: 'Users',
                    through: {
                        attributes: []
                    }
                }
            ]
        });
    }

    async updateClubSettings(userToken, clubId, {
        greetingText,
        associationMemberNumber,
        myTischtennisFedNickname,
        autoFetchRankings,
        countryCode,
        stateCode,
        memberDataQualityRequirements,
        feeRules,
        outgoingInvoicePrefix,
        outgoingInvoiceNextNumber,
        incomingInvoicePrefix,
        incomingInvoiceNextNumber
    }) {
        await checkAccess(userToken, clubId);
        const club = await Club.findByPk(clubId);
        if (!club) {
            throw new Error('clubnotfound');
        }
        const updates = { greetingText, associationMemberNumber };
        if (myTischtennisFedNickname !== undefined) updates.myTischtennisFedNickname = myTischtennisFedNickname || null;
        if (autoFetchRankings !== undefined) updates.autoFetchRankings = !!autoFetchRankings;
        if (countryCode !== undefined) updates.countryCode = this.normalizeCountryCode(countryCode);
        if (stateCode !== undefined) updates.stateCode = this.normalizeStateCode(stateCode);
        if (memberDataQualityRequirements !== undefined) {
            updates.memberDataQualityRequirements = this.normalizeMemberDataQualityRequirements(memberDataQualityRequirements);
        }
        if (feeRules !== undefined) {
            updates.feeRules = this.normalizeFeeRules(feeRules);
        }
        if (outgoingInvoicePrefix !== undefined) updates.outgoingInvoicePrefix = this.normalizeInvoicePrefix(outgoingInvoicePrefix, 'RE');
        if (incomingInvoicePrefix !== undefined) updates.incomingInvoicePrefix = this.normalizeInvoicePrefix(incomingInvoicePrefix, 'EI');
        if (outgoingInvoiceNextNumber !== undefined) updates.outgoingInvoiceNextNumber = this.normalizeInvoiceNextNumber(outgoingInvoiceNextNumber);
        if (incomingInvoiceNextNumber !== undefined) updates.incomingInvoiceNextNumber = this.normalizeInvoiceNextNumber(incomingInvoiceNextNumber);
        return await club.update(updates);
    }

    normalizeCountryCode(countryCode) {
        const normalized = String(countryCode || 'DE').trim().toUpperCase();
        return /^[A-Z]{2}$/.test(normalized) ? normalized : 'DE';
    }

    normalizeStateCode(stateCode) {
        const normalized = String(stateCode || '').trim().toUpperCase();
        return normalized || null;
    }

    normalizeMemberDataQualityRequirements(settings) {
        const defaults = {
            requireStreet: true,
            requirePostalCode: true,
            requireCity: true,
            requirePhone: true,
            requireEmail: true
        };

        if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
            return defaults;
        }

        return Object.fromEntries(
            Object.entries(defaults).map(([key, defaultValue]) => [
                key,
                typeof settings[key] === 'boolean' ? settings[key] : defaultValue
            ])
        );
    }

    normalizeFeeRules(rules) {
        if (!Array.isArray(rules)) {
            return [];
        }

        return rules
            .map((rule, index) => {
                if (!rule || typeof rule !== 'object' || Array.isArray(rule)) {
                    return null;
                }

                const code = String(rule.code || rule.contributionGroupCode || '').trim();
                const label = String(rule.label || '').trim();
                const amountCents = Number.parseInt(rule.amountCents ?? Math.round(Number(rule.amountEuro || 0) * 100), 10);
                const cycle = String(rule.cycle || 'monthly').trim().toLowerCase();
                const note = String(rule.note || '').trim();

                return {
                    id: String(rule.id || `${Date.now()}-${index}`),
                    code,
                    label,
                    amountCents: Number.isFinite(amountCents) && amountCents >= 0 ? amountCents : 0,
                    cycle: ['monthly', 'quarterly', 'half_yearly', 'yearly', 'one_time'].includes(cycle) ? cycle : 'monthly',
                    note: note || null,
                };
            })
            .filter((rule) => rule && (rule.code || rule.label || rule.amountCents > 0));
    }

    normalizeInvoicePrefix(prefix, fallback) {
        const normalized = String(prefix || fallback || '').trim().toUpperCase().slice(0, 24);
        return normalized || fallback;
    }

    normalizeInvoiceNextNumber(value) {
        const numeric = Number.parseInt(value, 10);
        return Number.isInteger(numeric) && numeric > 0 ? numeric : 1;
    }

    async approveUserClubAccess(userToken, clubId, toApproveUserId) {
        await checkAccess(userToken, clubId);
        const toApproveUserClub = await UserClub.findOne({
            where: {
                userId: toApproveUserId,
                clubId: clubId
            }
        });
        if (!toApproveUserClub) {
            throw new Error('norequest');
        }
        return await toApproveUserClub.update({ approved: true });
    }

    async requestAccessToClub(userId, clubId) {
        const access = await UserClub.findAll({
            where: {
                userId: userId,
                clubId: clubId,
            }
        });
        if (access.length > 0) {
            throw new Error('alreadyrequested');
        }
        const club = await Club.findOne({
            where: {
                id: clubId
            }
        });
        if (!club) {
            throw new Error('clubnotfound');
        }
        return await UserClub.create({
            userId: userId,
            clubId: clubId,
            approved: 0
        });
    }

    async getPendingUserApprovals(userToken, clubId) {
        await checkAccess(userToken, clubId);
        return await UserClub.findAll({
            where: {
                clubId: clubId,
                approved: 0
            },
            include: [
                {
                    model: User,
                    as: 'user',
                }
            ]
        });
    }

    async rejectUserClubAccess(userToken, clubId, toRejectUserId) {
        await checkAccess(userToken, clubId);
        const toRejectUserClub = await UserClub.findOne({
            where: {
                userId: toRejectUserId,
                clubId: clubId
            }
        });
        if (!toRejectUserClub) {
            throw new Error('norequest');
        }
        return await toRejectUserClub.destroy();
    }
}

export default new ClubService();
