import {
    ClubTeam,
    ClubTeamMember,
    League,
    Member,
    Season
} from '../models/index.js';
import SeasonService from './seasonService.js';
import { devLog } from '../utils/logger.js';

class ClubTeamService {
    static isMissingTeamLineupTable(error) {
        return error?.original?.code === 'ER_NO_SUCH_TABLE'
            && String(error?.original?.sqlMessage || '').includes('club_team_member');
    }
    /**
     * Holt alle ClubTeams für einen Verein, optional gefiltert nach Saison.
     * Wenn keine Saison-ID angegeben ist, wird die aktuelle Saison verwendet.
     * @param {number} clubId - Die ID des Vereins.
     * @param {number|null} seasonId - Optionale Saison-ID.
     * @returns {Promise<Array<ClubTeam>>} Eine Liste von ClubTeams.
     */
    static async getAllClubTeamsByClub(clubId, seasonId = null) {
        try {

            // Wenn keine Saison angegeben, verwende die aktuelle
            if (!seasonId) {
                const currentSeason = await SeasonService.getOrCreateCurrentSeason();
                seasonId = currentSeason.id;
            }

            const clubTeams = await ClubTeam.findAll({
                where: { clubId, seasonId },
                order: [['name', 'ASC']]
            });

            // Manuelle Datenanreicherung für Liga und Saison
            const enrichedClubTeams = [];
            for (const clubTeam of clubTeams) {
                const enrichedTeam = {
                    id: clubTeam.id,
                    name: clubTeam.name,
                    clubId: clubTeam.clubId,
                    leagueId: clubTeam.leagueId,
                    seasonId: clubTeam.seasonId,
                    myTischtennisTeamId: clubTeam.myTischtennisTeamId,
                    teamGender: clubTeam.teamGender,
                    teamAgeGroup: clubTeam.teamAgeGroup,
                    plannedLeagueName: clubTeam.plannedLeagueName,
                    createdAt: clubTeam.createdAt,
                    updatedAt: clubTeam.updatedAt,
                    league: { name: 'Unbekannt' },
                    season: { season: 'Unbekannt' }
                };

                // Lade Liga-Daten
                if (clubTeam.leagueId) {
                    const league = await League.findByPk(clubTeam.leagueId, { 
                        attributes: ['id', 'name', 'myTischtennisGroupId', 'association', 'groupname'] 
                    });
                    if (league) enrichedTeam.league = league;
                }

                // Lade Saison-Daten
                if (clubTeam.seasonId) {
                    const season = await Season.findByPk(clubTeam.seasonId, { attributes: ['season'] });
                    if (season) enrichedTeam.season = season;
                }

                enrichedClubTeams.push(enrichedTeam);
            }
            return enrichedClubTeams;
        } catch (error) {
            console.error('[ClubTeamService.getAllClubTeamsByClub] - Error:', error);
            throw error;
        }
    }

    /**
     * Holt ein ClubTeam anhand seiner ID
     * @param {number} clubTeamId - Die ID des ClubTeams
     * @returns {Promise<ClubTeam|null>} Das ClubTeam oder null, wenn nicht gefunden
     */
    static async getClubTeamById(clubTeamId) {
        try {
            const clubTeam = await ClubTeam.findByPk(clubTeamId, {
                include: [
                    {
                        model: League,
                        as: 'league',
                        attributes: ['id', 'name']
                    },
                    {
                        model: Season,
                        as: 'season',
                        attributes: ['id', 'season']
                    }
                ]
            });
            return clubTeam;
        } catch (error) {
            console.error('[ClubTeamService.getClubTeamById] - Error:', error);
            throw error;
        }
    }

    /**
     * Erstellt ein neues ClubTeam.
     * Wenn keine Saison-ID angegeben ist, wird die aktuelle Saison zugewiesen.
     * @param {object} clubTeamData - Die Daten des neuen ClubTeams (name, clubId, optional leagueId, seasonId).
     * @returns {Promise<ClubTeam>} Das erstellte ClubTeam.
     */
    static async createClubTeam(clubTeamData) {
        try {

            // Wenn keine Saison angegeben, verwende die aktuelle
            if (!clubTeamData.seasonId) {
                const currentSeason = await SeasonService.getOrCreateCurrentSeason();
                clubTeamData.seasonId = currentSeason.id;
            }

            const clubTeam = await ClubTeam.create(clubTeamData);
            return clubTeam;
        } catch (error) {
            console.error('[ClubTeamService.createClubTeam] - Error:', error);
            throw error;
        }
    }

    /**
     * Aktualisiert ein bestehendes ClubTeam.
     * @param {number} clubTeamId - Die ID des zu aktualisierenden ClubTeams.
     * @param {object} updateData - Die zu aktualisierenden Daten.
     * @returns {Promise<boolean>} True, wenn das ClubTeam aktualisiert wurde, sonst false.
     */
    static async updateClubTeam(clubTeamId, updateData) {
        try {
            const [updatedRowsCount] = await ClubTeam.update(updateData, {
                where: { id: clubTeamId }
            });
            return updatedRowsCount > 0;
        } catch (error) {
            console.error('[ClubTeamService.updateClubTeam] - Error:', error);
            throw error;
        }
    }

    /**
     * Löscht ein ClubTeam.
     * @param {number} clubTeamId - Die ID des zu löschenden ClubTeams.
     * @returns {Promise<boolean>} True, wenn das ClubTeam gelöscht wurde, sonst false.
     */
    static async deleteClubTeam(clubTeamId) {
        try {
            const deletedRows = await ClubTeam.destroy({
                where: { id: clubTeamId }
            });
            return deletedRows > 0;
        } catch (error) {
            console.error('[ClubTeamService.deleteClubTeam] - Error:', error);
            throw error;
        }
    }

    /**
     * Holt alle Ligen für einen Verein, optional gefiltert nach Saison.
     * Wenn keine Saison-ID angegeben ist, wird die aktuelle Saison verwendet.
     * @param {number} clubId - Die ID des Vereins.
     * @param {number|null} seasonId - Optionale Saison-ID.
     * @returns {Promise<Array<League>>} Eine Liste von Ligen.
     */
    static async getLeaguesByClub(clubId, seasonId = null) {
        try {

            // Wenn keine Saison angegeben, verwende die aktuelle
            if (!seasonId) {
                const currentSeason = await SeasonService.getOrCreateCurrentSeason();
                seasonId = currentSeason.id;
            }

            const leagues = await League.findAll({
                where: { clubId, seasonId },
                attributes: ['id', 'name', 'seasonId'],
                order: [['name', 'ASC']]
            });
            return leagues;
        } catch (error) {
            console.error('[ClubTeamService.getLeaguesByClub] - Error:', error);
            throw error;
        }
    }

    static async getTeamLineup(clubTeamId, lineupHalf = 'first_half') {
        try {
            const lineupEntries = await ClubTeamMember.findAll({
                where: { clubTeamId, lineupHalf },
                order: [['position', 'ASC']]
            });

            if (lineupEntries.length === 0) {
                return [];
            }

            const memberIds = [...new Set(
                lineupEntries
                    .map((entry) => Number(entry.memberId))
                    .filter((memberId) => Number.isInteger(memberId) && memberId > 0)
            )];

            const members = memberIds.length > 0
                ? await Member.findAll({
                    where: { id: memberIds }
                })
                : [];

            const memberById = new Map(
                members.map((member) => [Number(member.id), member])
            );

            return lineupEntries.map((entry) => {
                const plainEntry = entry.get({ plain: true });
                return {
                    ...plainEntry,
                    member: memberById.get(Number(entry.memberId)) || null
                };
            });
        } catch (error) {
            if (this.isMissingTeamLineupTable(error)) {
                return [];
            }
            console.error('[ClubTeamService.getTeamLineup] - Error:', error);
            throw error;
        }
    }

    static async replaceTeamLineup(clubTeamId, assignments, lineupHalf = 'first_half') {
        try {
            await ClubTeamMember.destroy({
                where: { clubTeamId, lineupHalf }
            });

            if (!Array.isArray(assignments) || assignments.length === 0) {
                return [];
            }

            const normalizedAssignments = assignments
                .filter((entry) => entry && entry.memberId)
                .map((entry, index) => ({
                    clubTeamId,
                    lineupHalf,
                    memberId: Number(entry.memberId),
                    position: Number(entry.position) || (index + 1)
                }));

            if (normalizedAssignments.length === 0) {
                return [];
            }

            await ClubTeamMember.bulkCreate(normalizedAssignments);
            return await this.getTeamLineup(clubTeamId, lineupHalf);
        } catch (error) {
            if (this.isMissingTeamLineupTable(error)) {
                const tableMissingError = new Error('teamlineuptablemissing');
                tableMissingError.code = 'TEAM_LINEUP_TABLE_MISSING';
                throw tableMissingError;
            }
            console.error('[ClubTeamService.replaceTeamLineup] - Error:', error);
            throw error;
        }
    }
}

export default ClubTeamService;
