import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
import html2canvas from 'html2canvas';

class PDFGenerator {
    constructor(margin = 20, columnGap = 10, t = null) {
        this.pdf = new jsPDF('p', 'mm', 'a4');
        this.margin = margin;
        this.columnGap = columnGap;
        this.pageHeight = 297 - margin * 2;
        this.columnWidth = (210 - margin * 2 - columnGap) / 2;
        this.position = margin;
        this.yPos = this.position;
        this.xPos = margin;
        this.isLeftColumn = true;
        this.COLUMN_START_TIME = margin;
        this.COLUMN_ACTIVITY = margin + 30;
        this.COLUMN_GROUP = margin + 100;
        this.COLUMN_DURATION = margin + 150;
        this.LINE_HEIGHT = 7;
        this.cursorY = margin;
        // Übersetzungsfunktion (optional)
        this.t = t || ((key) => {
            // Fallback zu deutschen Texten wenn keine Übersetzung vorhanden
            const fallbacks = {
                'pdfGenerator.trainingPlan': 'Trainingsplan',
                'pdfGenerator.date': 'Datum:',
                'pdfGenerator.time': 'Uhrzeit:',
                'pdfGenerator.startTime': 'Startzeit',
                'pdfGenerator.activityTimeBlock': 'Aktivität / Zeitblock',
                'pdfGenerator.group': 'Gruppe',
                'pdfGenerator.duration': 'Dauer (Min)',
                'pdfGenerator.timeBlock': 'Zeitblock',
                'pdfGenerator.phoneList': 'Telefonliste - Aktive Mitglieder',
                'pdfGenerator.nameFirstName': 'Name, Vorname',
                'pdfGenerator.birthDate': 'Geburtsdatum',
                'pdfGenerator.phoneNumber': 'Telefon-Nr.',
                'pdfGenerator.officialTournament': 'Offizielles Turnier',
                'pdfGenerator.member': 'Mitglied:',
                'pdfGenerator.hints': 'Hinweise:',
                'pdfGenerator.tournament': 'Turnier',
                'pdfGenerator.place': 'Platz',
                'pdfGenerator.player': 'Spieler',
                'pdfGenerator.points': 'Punkte',
                'pdfGenerator.sets': 'Sätze',
                'pdfGenerator.diff': 'Diff',
                'pdfGenerator.groupMatrices': 'Gruppen-Matrizen',
                'pdfGenerator.allGames': 'Alle Spiele',
                'pdfGenerator.noActivities': 'Keine Aktivitäten für diesen Trainingstag erfasst.',
                'pdfGenerator.groupLabel': 'Gruppe',
                'pdfGenerator.oneHourBefore': 'Eine Stunde vor Beginn der Konkurrenz in der Halle sein',
                'pdfGenerator.hallShoes': 'Hallenschuhe (dürfen auf Boden nicht abfärben)',
                'pdfGenerator.informTrainer': 'Da der Verein die Meldung übernehmen möchte, die Trainer mind. eine Woche vor dem Turnier über die Teilnahme informieren',
                'pdfGenerator.trainersPresent': 'Die Trainer probieren bei allen Turnieren anwesend zu sein.',
                'pdfGenerator.recommendations': 'Empfehlungen',
                'pdfGenerator.competition': 'Wettbewerb',
                'pdfGenerator.fee': 'Gebühr',
                'pdfGenerator.alsoPlayable': 'Ebenfalls spielbar',
                'pdfGenerator.venue': 'Austragungsort',
                'pdfGenerator.venues': 'Austragungsorte',
                'pdfGenerator.noWhiteJersey': 'Kein weißes Trikot',
                'pdfGenerator.sportShorts': 'Sportshorts (oder Sportröckchen), am besten auch nicht weiß',
                'pdfGenerator.waterBottle': 'Eine Flasche Wasser dabei haben',
                'pdfGenerator.overallRanking': 'Gesamt-Ranking (K.O.-Runden)',
                'pdfGenerator.round': 'Runde',
                'pdfGenerator.player1': 'Spieler 1',
                'pdfGenerator.player2': 'Spieler 2',
                'pdfGenerator.result': 'Ergebnis',
                'pdfGenerator.status': 'Status',
                'pdfGenerator.placement': 'Platzierung',
                'pdfGenerator.competitionName': 'Konkurrenz',
                'pdfGenerator.teamLineupTitle': 'Mannschaftsaufstellung',
                'pdfGenerator.clubLabel': 'Verein:',
                'pdfGenerator.teamNameLabel': 'Mannschaft:',
                'pdfGenerator.leagueLabel': 'Spielklasse:',
                'pdfGenerator.seasonLabel': 'Saison:',
                'pdfGenerator.periodLabel': 'Meldung für:',
                'pdfGenerator.teamGenderLabel': 'Team Geschlecht:',
                'pdfGenerator.teamAgeGroupLabel': 'Team Altersklasse:',
                'pdfGenerator.generatedAt': 'Erstellt:',
                'pdfGenerator.lineupQttr': '(Q)TTR',
                'pdfGenerator.plannedLeagueLabel': 'Geplante Spielklasse:'
            };
            return fallbacks[key] || key;
        });
    }

    async addSchedule(element) {
        const canvas = await html2canvas(element, {
            scale: 2,
            onclone: (clonedDoc) => {
                const clonedEl = clonedDoc.getElementById('schedule');
                if (clonedEl) clonedEl.style.fontSize = '12pt';
                // Klon des Wurzel-Elements
                const tbl = clonedDoc.getElementById(element.id);
                if (!tbl) return;

                // Alle Zellen und Überschriften-Elemente auswählen
                const cells = tbl.querySelectorAll('td, th');
                cells.forEach(cell => {
                    cell.style.fontSize = '12pt';
                });
            }
        });
        const imgData = canvas.toDataURL('image/png');
        const imgWidth = 210 - this.margin * 2;
        const imgHeight = (canvas.height * imgWidth) / canvas.width;
        let heightLeft = imgHeight;
        let position = this.margin;
        this.pdf.addImage(imgData, 'PNG', this.margin, position, imgWidth, imgHeight);
        this.pdf.setFontSize(12);
        heightLeft -= this.pageHeight;
        while (heightLeft >= 0) {
            position = heightLeft - imgHeight + this.margin;
            this.pdf.addPage();
            this.pdf.addImage(imgData, 'PNG', this.margin, position, imgWidth, imgHeight);
            heightLeft -= this.pageHeight;
        }
    }

    addNewPage() {
        this.pdf.addPage();
        this.xPos = this.margin;
        this.yPos = this.position;
        this.cursorY = this.margin;
        this.isLeftColumn = true;
    }

    addTitle(text) {
        // remember old settings
        const oldFont = this.pdf.getFont();
        const oldStyle = this.pdf.getFont().fontStyle;
        const oldSize = this.pdf.getFontSize();

        // set new
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(text, this.margin, this.cursorY);
        this.cursorY += 10;

        // restore
        this.pdf.setFont(oldFont.fontName, oldStyle);
        this.pdf.setFontSize(oldSize);
    }

    addHeader(clubName, formattedDate, formattedStartTime, formattedEndTime) {
        this.pdf.setFontSize(14);
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.text(`${clubName} - ${this.t('pdfGenerator.trainingPlan')}`, this.margin, this.yPos);
        this.yPos += 10;
        this.pdf.setFontSize(12);
        this.pdf.setFont('helvetica', 'normal');
        this.pdf.text(`${this.t('pdfGenerator.date')} ${formattedDate}`, this.margin, this.yPos);
        this.yPos += 7;
        this.pdf.text(`${this.t('pdfGenerator.time')} ${formattedStartTime} - ${formattedEndTime}`, this.margin, this.yPos);
        this.yPos += 10;
    }

    addTableHeaders() {
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.text(this.t('pdfGenerator.startTime'), this.COLUMN_START_TIME, this.yPos);
        this.pdf.text(this.t('pdfGenerator.activityTimeBlock'), this.COLUMN_ACTIVITY, this.yPos);
        this.pdf.text(this.t('pdfGenerator.group'), this.COLUMN_GROUP, this.yPos);
        this.pdf.text(this.t('pdfGenerator.duration'), this.COLUMN_DURATION, this.yPos);
        this.yPos += this.LINE_HEIGHT;
        this.pdf.setFont('helvetica', 'normal');
    }

    addTrainingPlan(clubName, trainingDate, trainingStart, trainingEnd, trainingPlan) {
        const formattedDate = new Date(trainingDate).toLocaleDateString('de-DE');
        const formattedStartTime = trainingStart ? trainingStart.slice(0, 5) : '';
        const formattedEndTime = trainingEnd ? trainingEnd.slice(0, 5) : '';
        this.addHeader(clubName, formattedDate, formattedStartTime, formattedEndTime);
        this.addTableHeaders();
        for (const item of trainingPlan) {
            if (item.isTimeblock) {
                this.addTimeBlock(item);
            } else {
                this.addActivity(item);
            }
            this.checkPageOverflow();
        }
    }

    addTimeBlock(item) {
        this.pdf.setFont('helvetica');
        this.pdf.text(item.startTime, this.COLUMN_START_TIME, this.yPos);
        this.pdf.text(this.t('pdfGenerator.timeBlock'), this.COLUMN_ACTIVITY, this.yPos);
        this.yPos += this.LINE_HEIGHT;
        this.pdf.setFont('helvetica', 'normal');
        if (item.groupActivities && item.groupActivities.length > 0) {
            this.addGroupActivities(item.groupActivities);
        }
    }

    addActivity(item) {
        const startTime = item.startTime;
        const activityName = item.predefinedActivity
            ? item.predefinedActivity.name
            : item.activity;
        const groupName = item.groupActivity ? item.groupActivity.name : '';
        const duration = item.duration ? item.duration.toString() : '';
        let text = '';
        if (item.durationText) {
            text = item.durationText + ' / ';
        }
        text += duration;
        this.pdf.text(startTime, this.COLUMN_START_TIME, this.yPos);
        this.pdf.text(activityName, this.COLUMN_ACTIVITY, this.yPos);
        this.pdf.text(groupName, this.COLUMN_GROUP, this.yPos);
        this.pdf.text(text, this.COLUMN_DURATION, this.yPos);
        this.yPos += this.LINE_HEIGHT;
        if (item.groupActivities && item.groupActivities.length > 0) {
            this.addGroupActivities(item.groupActivities);
        }
    }

    addGroupActivities(groupActivities) {
        for (const groupItem of groupActivities) {
            const activityName = groupItem.groupPredefinedActivity
                ? groupItem.groupPredefinedActivity.name
                : '';
            const groupName = groupItem.groupsGroupActivity
                ? groupItem.groupsGroupActivity.name
                : '';
            this.pdf.text('', this.COLUMN_START_TIME, this.yPos); // Leere Startzeit
            this.pdf.text(' - ' + activityName, this.COLUMN_ACTIVITY + 5, this.yPos); // Einrückung
            this.pdf.text(groupName, this.COLUMN_GROUP, this.yPos);
            this.pdf.text('', this.COLUMN_DURATION, this.yPos); // Leere Dauer
            this.yPos += this.LINE_HEIGHT;
            this.checkPageOverflow();
        }
    }

    checkPageOverflow() {
        if (this.yPos > this.pageHeight) {
            this.addNewPage();
        }
    }

    save(filename) {
        this.pdf.save(filename);
    }

    addPhoneList(members) {
        this.pdf.setFontSize(14);
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.text(this.t('pdfGenerator.phoneList'), this.margin, this.yPos);
        this.yPos += 10;
        this.addPhoneListHeaders();

        this.pdf.setFont('helvetica', 'normal');
        for (const member of members) {
            this.addPhoneListRow(member);
            this.checkPageOverflow();
        }
    }

    addPhoneListHeaders() {
        this.pdf.setFontSize(10);
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.text(this.t('pdfGenerator.nameFirstName'), this.margin, this.yPos);
        this.pdf.text(this.t('pdfGenerator.birthDate'), this.margin + 60, this.yPos);
        this.pdf.text(this.t('pdfGenerator.phoneNumber'), this.margin + 120, this.yPos);
        this.yPos += this.LINE_HEIGHT;
        this.pdf.setFont('helvetica', 'normal');
        this.pdf.setFontSize(10); // Sicherstellen, dass die Schriftgröße für die Einträge korrekt ist
    }

    addPhoneListRow(member) {
        const fullName = `${member.lastName}, ${member.firstName}`;
        const birthDate = member.birthDate ? new Date(member.birthDate).toLocaleDateString('de-DE') : '';
        
        // Sammle alle Telefonnummern aus contacts
        let phoneContacts = [];
        if (member.contacts && Array.isArray(member.contacts)) {
            phoneContacts = member.contacts
                .filter(c => c.type === 'phone' && c.value && String(c.value).trim() !== '')
                .sort((a, b) => {
                    // Primäre Telefonnummer zuerst
                    if (a.isPrimary && !b.isPrimary) return -1;
                    if (!a.isPrimary && b.isPrimary) return 1;
                    return 0;
                });
        }
        
        // Fallback auf altes phone-Feld für Rückwärtskompatibilität
        if (phoneContacts.length === 0 && member.phone) {
            phoneContacts.push({
                value: member.phone,
                isParent: false,
                parentName: null
            });
        }
        
        // Startposition für Name und Geburtsdatum
        const startYPos = this.yPos;
        
        // Sicherstellen, dass die Schriftgröße korrekt ist
        this.pdf.setFontSize(10);
        this.pdf.setFont('helvetica', 'normal');
        
        // Zeige Name und Geburtsdatum nur einmal am Anfang
        this.pdf.text(fullName, this.margin, startYPos);
        this.pdf.text(birthDate, this.margin + 60, startYPos);
        
        // Zeige alle Telefonnummern untereinander
        if (phoneContacts.length > 0) {
            let currentYPos = startYPos;
            
            phoneContacts.forEach((contact, index) => {
                // Telefonnummer in normaler Schriftgröße
                this.pdf.setFont('helvetica', 'normal');
                this.pdf.setFontSize(10);
                this.pdf.text(contact.value, this.margin + 120, currentYPos);
                
                // Y-Position nach der Telefonnummer erhöhen
                currentYPos += 4; // Höhe der Telefonnummer
                
                // Bei Elternteil-Nummern: Name in kleiner Schrift darunter
                if (contact.isParent) {
                    // Name in kleiner Schrift
                    this.pdf.setFont('helvetica', 'normal');
                    this.pdf.setFontSize(7); // Deutlich kleinere Schrift
                    let parentText = '';
                    if (contact.parentName) {
                        parentText = contact.parentName; // Nur der Name des Elternteils
                    } else {
                        parentText = 'Elternteil';
                    }
                    this.pdf.text(parentText, this.margin + 120, currentYPos);
                    
                    // Y-Position nach dem Namen erhöhen
                    currentYPos += 3; // Höhe des Namens
                    
                    // Zurück zur normalen Schriftgröße
                    this.pdf.setFontSize(10);
                }
                
                // Kleiner Abstand zur nächsten Nummer (nur wenn nicht die letzte)
                if (index < phoneContacts.length - 1) {
                    currentYPos += 1; // Minimaler Abstand zwischen Nummern
                }
            });
            
            // Aktualisiere yPos
            this.yPos = currentYPos;
        } else {
            // Keine Telefonnummern vorhanden
            this.yPos += this.LINE_HEIGHT;
        }
        
        // Zusätzlicher Abstand zwischen Mitgliedern
        this.yPos += 2;
    }

    addAddress(clubName, addressLines) {
        if (!this.addressY) {
            this.addressY = 30;
        }
        this.pdf.setFontSize(14);
        this.pdf.setFont(undefined, 'bold');
        this.pdf.text(clubName, 20, this.addressY);
        this.pdf.setFontSize(12);
        this.pdf.setFont(undefined, 'normal');
        addressLines.forEach(line => {
            this.addressY += 7;
            this.pdf.text(line, 20, this.addressY);
        });

        this.addressY += 10; // Abstand zur nächsten Adresse
    }

    async addScreenshot(element) {
        const canvas = await html2canvas(element, { scale: 2 });
        const imgData = canvas.toDataURL('image/png');
        const imgWidth = this.pageWidth;
        const imgHeight = (canvas.height * imgWidth) / canvas.width;
        this.pdf.addImage(imgData, 'PNG', this.margin, this.cursorY, imgWidth, imgHeight);
        this.cursorY += imgHeight + 10;
        if (this.cursorY > this.pdf.internal.pageSize.height - this.margin) {
            this.pdf.addPage();
            this.cursorY = this.margin;
        }
    }

    addTable(tableId, highlightName = '', excludeColumns = [], getCellPin = null) {
        this.pdf.setFontSize(11);
        
        // Wenn Spalten ausgeschlossen werden sollen, parse die Tabelle manuell
        if (excludeColumns.length > 0) {
            const table = document.querySelector(`#${tableId}`);
            if (!table) return;
            
            const headers = Array.from(table.querySelectorAll('thead th'))
                .map((th, index) => ({ text: th.textContent.trim(), index }))
                .filter(h => !excludeColumns.includes(h.index))
                .map(h => h.text);
            
            const rows = Array.from(table.querySelectorAll('tbody tr')).map(tr => {
                const sourceCells = Array.from(tr.querySelectorAll('td'))
                    .map((td, index) => ({ text: td.textContent.trim(), index }));

                return sourceCells
                    .filter(cell => !excludeColumns.includes(cell.index))
                    .map(cell => {
                        const pin = getCellPin ? getCellPin(sourceCells, cell.index) : null;
                        return pin ? { content: cell.text, pin } : cell.text;
                    });
            });
            
            autoTable(this.pdf, {
                head: [headers],
                body: rows,
                startY: this.cursorY,
                margin: { left: this.margin, right: this.margin },
                styles: { fontSize: this.pdf.getFontSize(), cellPadding: 3, overflow: 'linebreak' },
                headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
                theme: 'grid',
                tableWidth: 'auto',
                didParseCell: (data) => {
                    if (data.section === 'body') {
                        const cellText = Array.isArray(data.cell.text)
                            ? data.cell.text.join(' ')
                            : String(data.cell.text);
                        if (highlightName && cellText.includes(highlightName)) {
                            data.cell.styles.fontStyle = 'bold';
                        }
                    }
                },
                didDrawPage: (data) => {
                    this.cursorY = data.cursor.y + 10;
                },
                didDrawCell: (data) => {
                    const pin = data.cell.raw?.pin;
                    if (!pin || data.section !== 'body') return;

                    const fontSize = 7;
                    const teamText = Array.isArray(data.cell.text)
                        ? data.cell.text.join(' ')
                        : String(data.cell.text || '');
                    const pinText = `(${pin})`;
                    const padding = data.cell.padding('left');
                    const teamWidth = this.pdf.getTextWidth(teamText);
                    const pinWidth = this.pdf.getTextWidth(pinText) * (fontSize / this.pdf.getFontSize());
                    const pinX = data.cell.x + padding + teamWidth + 1;
                    const pinY = data.cell.y + data.cell.height - 3;

                    this.pdf.setFontSize(fontSize);
                    this.pdf.setTextColor(90);
                    if (pinX + pinWidth <= data.cell.x + data.cell.width - data.cell.padding('right')) {
                        this.pdf.text(pinText, pinX, pinY);
                    } else {
                        this.pdf.text(pinText, data.cell.x + padding, pinY);
                    }
                    this.pdf.setFontSize(11);
                    this.pdf.setTextColor(0);
                }
            });
        } else {
            // Ohne Ausschluss: normale HTML-Tabelle verwenden
            autoTable(this.pdf, {
                html: `#${tableId}`,
                startY: this.cursorY,
                margin: { left: this.margin, right: this.margin },
                styles: { fontSize: this.pdf.getFontSize() },
                headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left' },
                theme: 'grid',
                didParseCell: (data) => {
                    const cellText = Array.isArray(data.cell.text)
                        ? data.cell.text.join(' ')
                        : String(data.cell.text);
                    if (highlightName && cellText.includes(highlightName)) {
                        data.cell.styles.fontStyle = 'bold';
                    }
                },
                didDrawPage: (data) => {
                    this.cursorY = data.cursor.y + 10;
                }
            });
        }
    }

    addParticipantsSummary(tournamentTitle, tournamentDateText, groups) {
        // Header
        const title = tournamentTitle || this.t('pdfGenerator.officialTournament');
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(title, this.margin, this.cursorY);
        this.cursorY += 8;
        if (tournamentDateText) {
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(12);
            this.pdf.text(String(tournamentDateText), this.margin, this.cursorY);
            this.cursorY += 8;
        }

        // Tabelle mit Gruppierung
        const head = [[this.t('pdfGenerator.member').replace(':', ''), this.t('pdfGenerator.competitionName'), this.t('pdfGenerator.startTime'), this.t('pdfGenerator.status'), this.t('pdfGenerator.placement')]];
        const body = [];
        const rowStyles = [];
        
        for (const group of groups) {
            for (let i = 0; i < group.items.length; i++) {
                const item = group.items[i];
                const rowData = [
                    i === 0 ? group.memberName : '', // Name nur in erster Zeile
                    item.competitionName,
                    item.start || '–',
                    item.statusText || '',
                    item.placement || ''
                ];
                body.push(rowData);
                rowStyles.push({
                    isFirstRow: i === 0,
                    memberStyle: group.memberStyle,
                    competitionName: item.competitionName,
                    statusStyle: item.statusStyle
                });
            }
        }

        this.pdf.setFontSize(11);
        autoTable(this.pdf, {
            startY: this.cursorY,
            margin: { left: this.margin, right: this.margin },
            head,
            body,
            theme: 'grid',
            styles: { fontSize: 11 },
            headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left' },
            didParseCell: (data) => {
                if (data.section !== 'body') return;
                const rowStyle = rowStyles[data.row.index];
                
                // Formatierung für Mitgliedsname (erste Spalte, erste Zeile der Gruppe)
                if (data.column.index === 0 && rowStyle.isFirstRow) {
                    if (rowStyle.memberStyle === 'bold') data.cell.styles.fontStyle = 'bold';
                    else if (rowStyle.memberStyle === 'italic') data.cell.styles.fontStyle = 'italic';
                    else data.cell.styles.fontStyle = 'normal';
                }
                // Formatierung für Konkurrenzname (zweite Spalte)
                else if (data.column.index === 1) {
                    if (rowStyle.statusStyle === 'bold') data.cell.styles.fontStyle = 'bold';
                    else if (rowStyle.statusStyle === 'italic') data.cell.styles.fontStyle = 'italic';
                    else data.cell.styles.fontStyle = 'normal';
                }
            },
            didDrawPage: (data) => {
                this.cursorY = data.cursor.y + 10;
            }
        });
    }

    addMemberCompetitions(tournamentTitle, memberName, recommendedRows = [], otherRows = [], venues = []) {
        let y = this.margin;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(tournamentTitle || this.t('pdfGenerator.officialTournament'), this.margin, y);
        y += 9;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(12);
        this.pdf.text(`${this.t('pdfGenerator.member')} ${memberName}`, this.margin, y);
        y += 8;
        // Empfehlungen (fett)
        if (recommendedRows && recommendedRows.length) {
            this.pdf.setFont('helvetica', 'bold');
            this.pdf.setFontSize(13);
            this.pdf.text(this.t('pdfGenerator.recommendations'), this.margin, y);
            y += 7;
            this.pdf.setFont('helvetica', 'bold');
            this.pdf.setFontSize(12);
            this.pdf.text(this.t('pdfGenerator.competition'), this.margin, y);
            this.pdf.text(this.t('pdfGenerator.date').replace(':', ''), this.margin + 80, y);
            this.pdf.text(this.t('pdfGenerator.startTime'), this.margin + 120, y);
            this.pdf.text(this.t('pdfGenerator.fee'), this.margin + 160, y);
            y += 7;
            for (const r of recommendedRows) {
                this.pdf.text(r.name || '', this.margin, y);
                this.pdf.text(r.date || '–', this.margin + 80, y);
                this.pdf.text(r.time || '–', this.margin + 120, y);
                this.pdf.text(r.entryFee || '–', this.margin + 160, y);
                y += 7;
                if (y > this.pageHeight) {
                    this.addNewPage();
                    y = this.margin;
                }
            }
        }

        // Weitere spielbare Wettbewerbe (normal)
        if (otherRows && otherRows.length) {
            y += 5;
            if (y > this.pageHeight) { this.addNewPage(); y = this.margin; }
            this.pdf.setFont('helvetica', 'bold');
            this.pdf.setFontSize(13);
            this.pdf.text(this.t('pdfGenerator.alsoPlayable'), this.margin, y);
            y += 7;
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(12);
            for (const r of otherRows) {
                this.pdf.text(r.name || '', this.margin, y);
                this.pdf.text(r.date || '–', this.margin + 80, y);
                this.pdf.text(r.time || '–', this.margin + 120, y);
                this.pdf.text(r.entryFee || '–', this.margin + 160, y);
                y += 7;
                if (y > this.pageHeight) {
                    this.addNewPage();
                    y = this.margin;
                }
            }
        }
        // Austragungsort(e) direkt vor den Hinweisen
        const venueLines = Array.isArray(venues) ? venues.filter(Boolean) : [];
        if (venueLines.length) {
            const heading = venueLines.length === 1 ? this.t('pdfGenerator.venue') : this.t('pdfGenerator.venues');
            const maxWidth = 210 - this.margin * 2;
            if (y + 20 + venueLines.length * 6 > this.pageHeight) {
                this.addNewPage();
                y = this.margin;
            } else {
                y += 6;
            }
            this.pdf.setFont('helvetica', 'bold');
            this.pdf.setFontSize(13);
            this.pdf.text(`${heading}:`, this.margin, y);
            y += 7;
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(12);
            for (const v of venueLines) {
                const wrapped = this.pdf.splitTextToSize(String(v), maxWidth);
                for (const line of wrapped) {
                    this.pdf.text(line, this.margin, y);
                    y += 6;
                    if (y > this.pageHeight) {
                        this.addNewPage();
                        y = this.margin;
                        this.pdf.setFont('helvetica', 'normal');
                        this.pdf.setFontSize(12);
                    }
                }
            }
        }
        // Hinweise-Sektion
        const remainingForHints = 60; // Platz für Überschrift + Liste abschätzen
        if (y + remainingForHints > this.pageHeight) {
            this.addNewPage();
            y = this.margin;
        } else {
            y += 6;
        }
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(13);
        this.pdf.text(this.t('pdfGenerator.hints'), this.margin, y);
        y += 7;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(12);
        const maxWidth = 210 - this.margin * 2;
        const bullets = [
            this.t('pdfGenerator.oneHourBefore'),
            this.t('pdfGenerator.noWhiteJersey'),
            this.t('pdfGenerator.sportShorts'),
            this.t('pdfGenerator.hallShoes'),
            this.t('pdfGenerator.waterBottle'),
            this.t('pdfGenerator.informTrainer'),
        ];
        for (const b of bullets) {
            const lines = this.pdf.splitTextToSize(`- ${b}`, maxWidth);
            for (const line of lines) {
                this.pdf.text(line, this.margin, y);
                y += 6;
                if (y > this.pageHeight) {
                    this.addNewPage();
                    y = this.margin;
                    this.pdf.setFont('helvetica', 'bold');
                    this.pdf.setFontSize(12);
                }
            }
        }
        // Leerzeile vor dem Abschlusssatz
        if (y + 6 > this.pageHeight) {
            this.addNewPage();
            y = this.margin;
        } else {
            y += 6;
        }
        const finalLine = this.t('pdfGenerator.trainersPresent');
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(12);
        const finalLines = this.pdf.splitTextToSize(finalLine, maxWidth);
        for (const line of finalLines) {
            this.pdf.text(line, this.margin, y);
            y += 6;
            if (y > this.pageHeight) {
                this.addNewPage();
                y = this.margin;
                this.pdf.setFont('helvetica', 'bold');
                this.pdf.setFontSize(12);
            }
        }
        this.cursorY = y + 10;
    }

    addTournamentPDF(tournamentName, tournamentDate, groupsByClass, groupRankings, matchesByClassAndGroup, getPlayerName, knockoutRanking, participants, hasKnockoutMatches, knockoutMatches) {
        // Header
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(16);
        this.pdf.text(tournamentName || this.t('pdfGenerator.tournament'), this.margin, this.cursorY);
        this.cursorY += 8;
        
        if (tournamentDate) {
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(12);
            const formattedDate = new Date(tournamentDate).toLocaleDateString('de-DE', {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit'
            });
            this.pdf.text(`${this.t('pdfGenerator.date')} ${formattedDate}`, this.margin, this.cursorY);
            this.cursorY += 10;
        }

        // 1. Gesamt-Ranking nach Klassen (nur Platz und Spieler)
        // knockoutRanking und participants werden als zusätzliche Parameter übergeben
        // Verwende K.O.-Ranking nur wenn es vorhanden ist UND K.O.-Runden existieren
        const useKnockoutRanking = knockoutRanking && knockoutRanking.length > 0 && hasKnockoutMatches;
        this.addTournamentClassRankings(groupsByClass, groupRankings, getPlayerName, useKnockoutRanking ? knockoutRanking : null, participants);
        
        // 2. Gruppen-Matrizen mit Ergebnissen (neue Seite)
        this.addTournamentGroupMatrices(groupsByClass, groupRankings, getPlayerName);
        
        // 4. Alle Spiele nach Klasse und Gruppe sortiert (inkl. K.O.-Runden)
        this.addTournamentMatches(matchesByClassAndGroup, getPlayerName, knockoutMatches);
    }

    addTournamentClassRankings(groupsByClass, groupRankings, getPlayerName, knockoutRanking, participants) {
        // Wenn K.O.-Runden vorhanden sind, verwende diese für das Ranking
        if (knockoutRanking && knockoutRanking.length > 0) {
            // Erstelle Mapping von Member-ID zu classId
            // Für interne Teilnehmer: member.id -> classId
            const memberClassMap = {};
            if (participants) {
                participants.forEach(p => {
                    // Interne Teilnehmer haben ein member-Objekt
                    if (p.member && p.member.id) {
                        memberClassMap[p.member.id] = p.classId;
                    }
                });
            }
            
            // Gruppiere K.O.-Ranking nach Klassen
            // entry.classId sollte bereits vorhanden sein (aus extendedRankingList)
            const rankingByClass = {};
            knockoutRanking.forEach(entry => {
                // Verwende classId direkt aus entry, falls vorhanden
                let classId = entry.classId;
                
                // Fallback: Suche über memberId, falls classId nicht vorhanden
                if (classId == null && entry.member) {
                    const memberId = entry.member.id;
                    if (memberId && participants) {
                        // Suche im Mapping
                        classId = memberClassMap[memberId] || null;
                        
                        // Falls nicht gefunden, suche direkt in participants
                        if (!classId) {
                            const participant = participants.find(p => 
                                p.member && p.member.id === memberId
                            );
                            if (participant) {
                                classId = participant.classId;
                            }
                        }
                    }
                }
                
                const classKey = classId != null ? String(classId) : 'null';
                
                if (!rankingByClass[classKey]) {
                    rankingByClass[classKey] = [];
                }
                
                const playerName = entry.member 
                    ? `${entry.member.firstName || ''} ${entry.member.lastName || ''}`.trim()
                    : getPlayerName(entry.player || entry);
                
                rankingByClass[classKey].push({
                    position: entry.position,
                    name: playerName
                });
            });
            
            // Sortiere innerhalb jeder Klasse nach Position
            Object.keys(rankingByClass).forEach(classKey => {
                rankingByClass[classKey].sort((a, b) => a.position - b.position);
            });
            
            // Zeige Rankings nach Klassen (sortiert nach classId)
            Object.entries(rankingByClass).sort((a, b) => {
                const aNum = a[0] === 'null' ? 999999 : parseInt(a[0]);
                const bNum = b[0] === 'null' ? 999999 : parseInt(b[0]);
                return aNum - bNum;
            }).forEach(([classId, players]) => {
                const className = classId !== 'null' && classId !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classId) : null;
                
                // Prüfe ob neue Seite nötig
                if (this.cursorY > 250) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }
                
                // Klassen-Überschrift
                if (className) {
                    this.pdf.setFont('helvetica', 'bold');
                    this.pdf.setFontSize(14);
                    this.pdf.text(className, this.margin, this.cursorY);
                    this.cursorY += 10;
                }
                
                // Zeige Spieler
                players.forEach(player => {
                    if (this.cursorY > 280) {
                        this.addNewPage();
                        this.cursorY = this.margin;
                        // Klassen-Überschrift erneut anzeigen bei Seitenwechsel
                        if (className) {
                            this.pdf.setFont('helvetica', 'bold');
                            this.pdf.setFontSize(14);
                            this.pdf.text(className, this.margin, this.cursorY);
                            this.cursorY += 10;
                        }
                    }
                    
                    this.pdf.setFont('helvetica', 'normal');
                    this.pdf.setFontSize(11);
                    const playerText = `${player.position}. ${player.name}`;
                    this.pdf.text(playerText, this.margin, this.cursorY);
                    this.cursorY += 7;
                });
                
                // Abstand nach Klasse
                this.cursorY += 5;
            });
        } else {
            // Fallback: Verwende Gruppen-Rankings (nur wenn keine K.O.-Runden)
            // Aber: Wenn es K.O.-Runden gibt, aber rankingList leer ist, bedeutet das,
            // dass die K.O.-Runden noch nicht abgeschlossen sind
            // In diesem Fall sollten wir trotzdem die Gruppen-Rankings verwenden
            Object.entries(groupsByClass).forEach(([classId, groups]) => {
                const className = classId !== 'null' && classId !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classId) : null;
                
                // Prüfe ob neue Seite nötig
                if (this.cursorY > 250) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }
                
                // Klassen-Überschrift
                if (className) {
                    this.pdf.setFont('helvetica', 'bold');
                    this.pdf.setFontSize(14);
                    this.pdf.text(className, this.margin, this.cursorY);
                    this.cursorY += 10;
                }
                
                // Sammle alle Spieler aus allen Gruppen dieser Klasse
                // WICHTIG: Zeige alle Spieler, nicht nur die ersten Plätze
                const allPlayers = [];
                groups.forEach(group => {
                    const rankings = groupRankings[group.groupId] || [];
                    rankings.forEach(player => {
                        allPlayers.push({
                            position: player.position,
                            name: player.name,
                            seeded: player.seeded
                        });
                    });
                });
                
                // Sortiere nach Position (1, 1, 2, 2, 3, 3, etc.)
                allPlayers.sort((a, b) => {
                    if (a.position !== b.position) {
                        return a.position - b.position;
                    }
                    // Bei gleicher Position alphabetisch sortieren
                    return a.name.localeCompare(b.name);
                });
                
                // Erstelle einfache Liste: nur Platz und Spieler
                allPlayers.forEach(player => {
                    if (this.cursorY > 280) {
                        this.addNewPage();
                        this.cursorY = this.margin;
                        // Klassen-Überschrift erneut anzeigen bei Seitenwechsel
                        if (className) {
                            this.pdf.setFont('helvetica', 'bold');
                            this.pdf.setFontSize(14);
                            this.pdf.text(className, this.margin, this.cursorY);
                            this.cursorY += 10;
                        }
                    }
                    
                    this.pdf.setFont('helvetica', 'normal');
                    this.pdf.setFontSize(11);
                    const playerText = `${player.position}. ${player.seeded ? '★ ' : ''}${player.name}`;
                    this.pdf.text(playerText, this.margin, this.cursorY);
                    this.cursorY += 7;
                });
                
                // Abstand nach Klasse
                this.cursorY += 5;
            });
        }
    }

    addTournamentTables(groupsByClass, groupRankings, getPlayerName) {
        // Für jede Klasse
        Object.entries(groupsByClass).forEach(([classId, groups]) => {
            const className = classId !== 'null' && classId !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classId) : null;
            
            // Für jede Gruppe
            groups.forEach(group => {
                if (this.cursorY > 250) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }
                
                // Überschrift
                this.pdf.setFont('helvetica', 'bold');
                this.pdf.setFontSize(12);
                let title = `${this.t('pdfGenerator.groupLabel')} ${group.groupNumber}`;
                if (className) {
                    title = `${className} - ${title}`;
                }
                this.pdf.text(title, this.margin, this.cursorY);
                this.cursorY += 8;

                // Tabelle mit Rankings
                const rankings = groupRankings[group.groupId] || [];
                if (rankings.length > 0) {
                    const head = [[this.t('pdfGenerator.place'), this.t('pdfGenerator.player'), this.t('pdfGenerator.points'), this.t('pdfGenerator.sets'), this.t('pdfGenerator.diff')]];
                    const body = rankings.map(p => [
                        `${p.position}.`,
                        (p.seeded ? '★ ' : '') + p.name,
                        p.points.toString(),
                        `${p.setsWon}:${p.setsLost}`,
                        (p.setDiff >= 0 ? '+' : '') + p.setDiff.toString()
                    ]);

                    autoTable(this.pdf, {
                        startY: this.cursorY,
                        margin: { left: this.margin, right: this.margin },
                        head,
                        body,
                        theme: 'grid',
                        styles: { fontSize: 10 },
                        headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
                        didDrawPage: (data) => {
                            this.cursorY = data.cursor.y + 10;
                        }
                    });
                    this.cursorY += 5;
                }
            });
        });
    }

    addTournamentKnockoutRanking(knockoutRanking, getPlayerName) {
        // Prüfe ob neue Seite nötig
        if (this.cursorY > 200) {
            this.addNewPage();
            this.cursorY = this.margin;
        }

        // Überschrift
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(this.t('pdfGenerator.overallRanking'), this.margin, this.cursorY);
        this.cursorY += 10;

        // Ranking-Tabelle
        const head = [[this.t('pdfGenerator.place'), this.t('pdfGenerator.player')]];
        const body = knockoutRanking.map(entry => {
            const playerName = entry.member 
                ? `${entry.member.firstName || ''} ${entry.member.lastName || ''}`.trim()
                : getPlayerName(entry.player || entry);
            return [
                `${entry.position}.`,
                playerName
            ];
        });

        autoTable(this.pdf, {
            startY: this.cursorY,
            margin: { left: this.margin, right: this.margin },
            head,
            body,
            theme: 'grid',
            styles: { fontSize: 11 },
            headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
            didDrawPage: (data) => {
                this.cursorY = data.cursor.y + 10;
            }
        });
        this.cursorY += 5;
    }

    addTournamentGroupMatrices(groupsByClass, groupRankings, getPlayerName) {
        // Neue Seite für Matrizen
        this.addNewPage();
        this.cursorY = this.margin;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(this.t('pdfGenerator.groupMatrices'), this.margin, this.cursorY);
        this.cursorY += 10;

        // Für jede Klasse
        Object.entries(groupsByClass).forEach(([classId, groups]) => {
            const className = classId !== 'null' && classId !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classId) : null;
            
            // Für jede Gruppe
            groups.forEach(group => {
                if (this.cursorY > 200) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }
                
                const rankings = groupRankings[group.groupId] || [];
                if (rankings.length === 0) return;

                // Überschrift
                this.pdf.setFont('helvetica', 'bold');
                this.pdf.setFontSize(11);
                let title = `${this.t('pdfGenerator.groupLabel')} ${group.groupNumber}`;
                if (className) {
                    title = `${className} - ${title}`;
                }
                this.pdf.text(title, this.margin, this.cursorY);
                this.cursorY += 7;

                // Matrix erstellen
                const head = [['', ...rankings.map((p, idx) => `G${String.fromCharCode(96 + group.groupNumber)}${idx + 1}`)]];
                const body = rankings.map((player, idx) => {
                    const row = [`G${String.fromCharCode(96 + group.groupNumber)}${idx + 1} ${(player.seeded ? '★ ' : '') + player.name}`];
                    rankings.forEach((opponent, oppIdx) => {
                        if (idx === oppIdx) {
                            row.push('-');
                        } else {
                            // Finde Match-Ergebnis
                            const match = this.findMatchResult ? this.findMatchResult(player.id, opponent.id, group.groupId) : null;
                            row.push(match || '-');
                        }
                    });
                    return row;
                });

                autoTable(this.pdf, {
                    startY: this.cursorY,
                    margin: { left: this.margin, right: this.margin },
                    head,
                    body,
                    theme: 'grid',
                    styles: { fontSize: 8 },
                    headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
                    columnStyles: {
                        0: { cellWidth: 50 }
                    },
                    didDrawPage: (data) => {
                        this.cursorY = data.cursor.y + 10;
                    }
                });
                this.cursorY += 5;
            });
        });
    }

    addTournamentMatches(matchesByClassAndGroup, getPlayerName, knockoutMatches = []) {
        // Neue Seite für Spiele
        this.addNewPage();
        this.cursorY = this.margin;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(14);
        this.pdf.text(this.t('pdfGenerator.allGames'), this.margin, this.cursorY);
        this.cursorY += 10;

        // Für jede Klasse
        Object.entries(matchesByClassAndGroup).forEach(([classId, groups]) => {
            const className = classId !== 'null' && classId !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classId) : null;
            
            // Für jede Gruppe
            Object.entries(groups).forEach(([groupId, matches]) => {
                if (matches.length === 0) return;
                
                if (this.cursorY > 200) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }

                // Überschrift
                this.pdf.setFont('helvetica', 'bold');
                this.pdf.setFontSize(11);
                let title = `Gruppe ${matches[0].groupNumber || groupId}`;
                if (className) {
                    title = `${className} - ${title}`;
                }
                this.pdf.text(title, this.margin, this.cursorY);
                this.cursorY += 7;

                // Spiele-Tabelle
                const head = [[this.t('pdfGenerator.round'), this.t('pdfGenerator.player1'), this.t('pdfGenerator.player2'), this.t('pdfGenerator.result'), this.t('pdfGenerator.sets')]];
                const body = matches.map(m => [
                    m.groupRound?.toString() || '-',
                    getPlayerName(m.player1),
                    getPlayerName(m.player2),
                    m.isFinished ? (m.result || '-') : '-',
                    this.formatSets(m)
                ]);

                autoTable(this.pdf, {
                    startY: this.cursorY,
                    margin: { left: this.margin, right: this.margin },
                    head,
                    body,
                    theme: 'grid',
                    styles: { fontSize: 9 },
                    headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
                    didDrawPage: (data) => {
                        this.cursorY = data.cursor.y + 10;
                    }
                });
                this.cursorY += 5;
            });
        });
        
        // K.O.-Runden hinzufügen (wenn vorhanden)
        if (knockoutMatches && knockoutMatches.length > 0) {
            // Gruppiere K.O.-Matches nach Klassen
            const knockoutMatchesByClass = {};
            knockoutMatches.forEach(match => {
                const classKey = match.classId != null ? String(match.classId) : 'null';
                if (!knockoutMatchesByClass[classKey]) {
                    knockoutMatchesByClass[classKey] = [];
                }
                knockoutMatchesByClass[classKey].push(match);
            });
            
            // Sortiere Klassen
            const sortedClasses = Object.keys(knockoutMatchesByClass).sort((a, b) => {
                const aNum = a === 'null' ? 999999 : parseInt(a);
                const bNum = b === 'null' ? 999999 : parseInt(b);
                return aNum - bNum;
            });
            
            // Für jede Klasse
            sortedClasses.forEach(classKey => {
                const classMatches = knockoutMatchesByClass[classKey];
                const className = classKey !== 'null' && classKey !== 'undefined' && this.getClassNameForId ? this.getClassNameForId(classKey) : null;
                
                // Sortiere Matches nach Runde (frühere Runden zuerst: Achtelfinale, Viertelfinale, Halbfinale, Finale)
                const getRoundType = (roundName) => {
                    if (!roundName) return 999;
                    if (roundName.includes('Achtelfinale')) return 0;
                    if (roundName.includes('Viertelfinale')) return 1;
                    if (roundName.includes('Halbfinale')) return 2;
                    if (roundName.includes('Finale')) return 3;
                    // Für Runden wie "6-Runde", "8-Runde" etc. - extrahiere die Zahl
                    const numberMatch = roundName.match(/(\d+)-Runde/);
                    if (numberMatch) {
                        const num = parseInt(numberMatch[1]);
                        // Größere Zahlen = frühere Runden, also umgekehrt sortieren
                        return -num; // Negativ, damit größere Zahlen zuerst kommen
                    }
                    return 999; // Unbekannte Runden zuletzt
                };
                
                classMatches.sort((a, b) => {
                    const aRoundType = getRoundType(a.round);
                    const bRoundType = getRoundType(b.round);
                    if (aRoundType !== bRoundType) {
                        return aRoundType - bRoundType;
                    }
                    // Wenn gleicher Typ, alphabetisch sortieren
                    return (a.round || '').localeCompare(b.round || '');
                });
                
                if (this.cursorY > 200) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                }
                
                // Überschrift
                this.pdf.setFont('helvetica', 'bold');
                this.pdf.setFontSize(11);
                let title = 'K.-o.-Runde';
                if (className) {
                    title = `${className} - ${title}`;
                }
                this.pdf.text(title, this.margin, this.cursorY);
                this.cursorY += 7;
                
                // Spiele-Tabelle
                const head = [[this.t('pdfGenerator.round'), this.t('pdfGenerator.player1'), this.t('pdfGenerator.player2'), this.t('pdfGenerator.result'), this.t('pdfGenerator.sets')]];
                const body = classMatches.map(m => [
                    m.round || '-',
                    getPlayerName(m.player1),
                    getPlayerName(m.player2),
                    m.isFinished ? (m.result || '-') : '-',
                    this.formatSets(m)
                ]);
                
                autoTable(this.pdf, {
                    startY: this.cursorY,
                    margin: { left: this.margin, right: this.margin },
                    head,
                    body,
                    theme: 'grid',
                    styles: { fontSize: 9 },
                    headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' },
                    didDrawPage: (data) => {
                        this.cursorY = data.cursor.y + 10;
                    }
                });
                this.cursorY += 5;
            });
        }
    }

    getClassNameForId(classId, groupsByClass) {
        // Versuche, den Klassennamen zu finden
        // Dies sollte von außen übergeben werden, aber als Fallback:
        return `Klasse ${classId}`;
    }

    findMatchResult(player1Id, player2Id, groupId) {
        // Diese Methode sollte von außen übergeben werden
        // Für jetzt: Rückgabe von null
        return null;
    }

    formatSets(match) {
        if (!match.tournamentResults || match.tournamentResults.length === 0) {
            return '-';
        }
        return match.tournamentResults
            .sort((a, b) => a.set - b.set)
            .map(r => `${Math.abs(r.pointsPlayer1)}:${Math.abs(r.pointsPlayer2)}`)
            .join(', ');
    }

    addTrainingDaySummary(clubName, trainingDate, trainingStart, trainingEnd, members, activities, activityMembersMap, groupActivityMembersMap, participantMapByMemberId, groups, trainingPlan = [], memberGroupsMap = {}) {
        // Header
        const formattedDate = new Date(trainingDate).toLocaleDateString('de-DE');
        const formattedStartTime = trainingStart ? trainingStart.slice(0, 5) : '';
        const formattedEndTime = trainingEnd ? trainingEnd.slice(0, 5) : '';
        
        this.pdf.setFontSize(14);
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.text(`${clubName} - Trainingstag`, this.margin, this.cursorY);
        this.cursorY += 8;
        this.pdf.setFontSize(12);
        this.pdf.setFont('helvetica', 'normal');
        this.pdf.text(`Datum: ${formattedDate}`, this.margin, this.cursorY);
        this.cursorY += 7;
        if (formattedStartTime && formattedEndTime) {
            this.pdf.text(`Uhrzeit: ${formattedStartTime} - ${formattedEndTime}`, this.margin, this.cursorY);
            this.cursorY += 7;
        }
        this.cursorY += 5;

        // Debug-Ausgaben
        console.log('[addTrainingDaySummary] members:', members?.length || 0);
        console.log('[addTrainingDaySummary] activities:', activities?.length || 0);
        console.log('[addTrainingDaySummary] activityMembersMap:', activityMembersMap);
        console.log('[addTrainingDaySummary] participantMapByMemberId:', participantMapByMemberId);

        // Erstelle Mapping: memberId -> Liste von Aktivitäten
        const memberActivitiesMap = new Map();
        
        // Initialisiere für alle Teilnehmer
        members.forEach(member => {
            if (member && member.id) {
                memberActivitiesMap.set(member.id, []);
            }
        });

        // Erstelle umgekehrtes Mapping: participantId -> memberId (einmalig)
        const participantToMemberMap = {};
        if (participantMapByMemberId) {
            Object.keys(participantMapByMemberId).forEach(memberId => {
                const participantId = participantMapByMemberId[memberId];
                if (participantId) {
                    participantToMemberMap[participantId] = parseInt(memberId);
                }
            });
        }

        // Erstelle Mapping von activityId zu startTime aus trainingPlan
        const activityIdToStartTime = new Map();
        trainingPlan.forEach(item => {
            if (item && item.id && item.startTime) {
                activityIdToStartTime.set(item.id, item.startTime);
            }
        });

        // Durchlaufe alle Aktivitäten
        let activitiesProcessed = 0;
        let activitiesWithMembers = 0;
        activities.forEach(activity => {
            if (!activity || !activity.id) return;
            activitiesProcessed++;
            
            const activityName = activity.predefinedActivity 
                ? activity.predefinedActivity.name 
                : (activity.description || 'Unbekannte Aktivität');
            // Verwende startTime aus trainingPlan, falls vorhanden, sonst leer
            const activityStartTime = activityIdToStartTime.get(activity.id) || activity.startTime || '';
            const activityDuration = activity.duration ? `${activity.duration} Min` : '';
            
            // Finde alle Teilnehmer dieser Aktivität
            const participantIds = activityMembersMap[activity.id];
            let hasDirectAssignments = false;
            
            if (participantIds) {
                // Handle both Set and Array
                const idsArray = participantIds instanceof Set ? Array.from(participantIds) : (Array.isArray(participantIds) ? participantIds : []);
                if (idsArray.length > 0) {
                    hasDirectAssignments = true;
                    activitiesWithMembers++;
                    idsArray.forEach(participantId => {
                        // Finde memberId für diesen participantId
                        const memberId = participantToMemberMap[participantId];
                        if (memberId) {
                            if (!memberActivitiesMap.has(memberId)) {
                                memberActivitiesMap.set(memberId, []);
                            }
                            memberActivitiesMap.get(memberId).push({
                                name: activityName,
                                startTime: activityStartTime,
                                duration: activityDuration
                            });
                        } else {
                            console.log('[addTrainingDaySummary] Kein memberId gefunden für participantId:', participantId);
                        }
                    });
                }
            }
            
            // Wenn keine direkten Zuordnungen vorhanden sind, verwende Gruppen-Zuordnung
            if (!hasDirectAssignments) {
                const activityGroupId = activity.groupActivity ? activity.groupActivity.id : null;
                
                if (activityGroupId) {
                    // Aktivität hat eine Gruppe: nehme alle Members dieser Gruppe
                    members.forEach(member => {
                        if (member && member.id) {
                            const memberGroupId = memberGroupsMap[member.id];
                            // Prüfe ob memberGroupId als String oder Number vorliegt
                            const memberGroupIdStr = memberGroupId ? String(memberGroupId) : '';
                            const activityGroupIdStr = String(activityGroupId);
                            
                            if (memberGroupIdStr === activityGroupIdStr) {
                                if (!memberActivitiesMap.has(member.id)) {
                                    memberActivitiesMap.set(member.id, []);
                                }
                                memberActivitiesMap.get(member.id).push({
                                    name: activityName,
                                    startTime: activityStartTime,
                                    duration: activityDuration
                                });
                            }
                        }
                    });
                } else {
                    // Aktivität hat keine Gruppe: nehme alle Teilnehmer
                    members.forEach(member => {
                        if (member && member.id) {
                            if (!memberActivitiesMap.has(member.id)) {
                                memberActivitiesMap.set(member.id, []);
                            }
                            memberActivitiesMap.get(member.id).push({
                                name: activityName,
                                startTime: activityStartTime,
                                duration: activityDuration
                            });
                        }
                    });
                }
            }
        });
        console.log('[addTrainingDaySummary] Aktivitäten verarbeitet:', activitiesProcessed, 'mit Mitgliedern:', activitiesWithMembers);

        // Durchlaufe alle Gruppenaktivitäten
        // WICHTIG: Auch aus Zeitblöcken, daher trainingPlan verwenden statt activities
        if (groupActivityMembersMap && Object.keys(groupActivityMembersMap).length > 0) {
            // Finde Gruppenaktivitäten in trainingPlan (auch in Zeitblöcken)
            trainingPlan.forEach(activity => {
                if (!activity || !activity.groupActivities) return;
                
                activity.groupActivities.forEach(groupActivity => {
                    if (!groupActivity || !groupActivity.id) return;
                    
                    const activityName = groupActivity.groupPredefinedActivity
                        ? groupActivity.groupPredefinedActivity.name
                        : (groupActivity.description || 'Unbekannte Gruppenaktivität');
                    // Verwende startTime aus trainingPlan für die übergeordnete Aktivität
                    const activityStartTime = activityIdToStartTime.get(activity.id) || activity.startTime || '';
                    const activityDuration = activity.duration ? `${activity.duration} Min` : '';
                    
                    // Finde alle Teilnehmer dieser Gruppenaktivität
                    const participantIds = groupActivityMembersMap[groupActivity.id];
                    let hasDirectGroupActivityAssignments = false;
                    
                    if (participantIds) {
                        // Handle both Set and Array
                        const idsArray = participantIds instanceof Set ? Array.from(participantIds) : (Array.isArray(participantIds) ? participantIds : []);
                        if (idsArray.length > 0) {
                            hasDirectGroupActivityAssignments = true;
                            idsArray.forEach(participantId => {
                                // Finde memberId für diesen participantId
                                const memberId = participantToMemberMap[participantId];
                                if (memberId) {
                                    if (!memberActivitiesMap.has(memberId)) {
                                        memberActivitiesMap.set(memberId, []);
                                    }
                                    memberActivitiesMap.get(memberId).push({
                                        name: activityName,
                                        startTime: activityStartTime,
                                        duration: activityDuration
                                    });
                                }
                            });
                        }
                    }
                    
                    // Wenn keine direkten Zuordnungen vorhanden sind, verwende Gruppen-Zuordnung
                    if (!hasDirectGroupActivityAssignments) {
                        const groupActivityGroupId = groupActivity.groupsGroupActivity ? groupActivity.groupsGroupActivity.id : null;
                        
                        if (groupActivityGroupId) {
                            // Gruppenaktivität hat eine Gruppe: nehme alle Members dieser Gruppe
                            members.forEach(member => {
                                if (member && member.id) {
                                    const memberGroupId = memberGroupsMap[member.id];
                                    // Prüfe ob memberGroupId als String oder Number vorliegt
                                    const memberGroupIdStr = memberGroupId ? String(memberGroupId) : '';
                                    const groupActivityGroupIdStr = String(groupActivityGroupId);
                                    
                                    if (memberGroupIdStr === groupActivityGroupIdStr) {
                                        if (!memberActivitiesMap.has(member.id)) {
                                            memberActivitiesMap.set(member.id, []);
                                        }
                                        memberActivitiesMap.get(member.id).push({
                                            name: activityName,
                                            startTime: activityStartTime,
                                            duration: activityDuration
                                        });
                                    }
                                }
                            });
                        } else {
                            // Gruppenaktivität hat keine Gruppe: nehme alle Teilnehmer
                            members.forEach(member => {
                                if (member && member.id) {
                                    if (!memberActivitiesMap.has(member.id)) {
                                        memberActivitiesMap.set(member.id, []);
                                    }
                                    memberActivitiesMap.get(member.id).push({
                                        name: activityName,
                                        startTime: activityStartTime,
                                        duration: activityDuration
                                    });
                                }
                            });
                        }
                    }
                });
            });
        }

        // Sortiere Mitglieder alphabetisch
        const sortedMembers = members
            .filter(m => m && m.id && memberActivitiesMap.has(m.id))
            .sort((a, b) => {
                const lastNameCompare = (a.lastName || '').localeCompare(b.lastName || '');
                if (lastNameCompare !== 0) return lastNameCompare;
                return (a.firstName || '').localeCompare(b.firstName || '');
            });
        
        console.log('[addTrainingDaySummary] Mitglieder mit Aktivitäten:', sortedMembers.length);
        console.log('[addTrainingDaySummary] memberActivitiesMap:', Array.from(memberActivitiesMap.entries()).map(([id, acts]) => ({ id, count: acts.length })));

        // Zeige für jeden Teilnehmer seine Aktivitäten
        sortedMembers.forEach(member => {
            const memberActivities = memberActivitiesMap.get(member.id);
            if (!memberActivities || memberActivities.length === 0) return;

            // Prüfe ob neue Seite nötig
            if (this.cursorY > 250) {
                this.addNewPage();
                this.cursorY = this.margin;
            }

            // Mitgliedsname
            this.pdf.setFont('helvetica', 'bold');
            this.pdf.setFontSize(12);
            const memberName = `${member.firstName || ''} ${member.lastName || ''}`.trim();
            this.pdf.text(memberName, this.margin, this.cursorY);
            this.cursorY += 8;

            // Aktivitäten
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(10);
            memberActivities.forEach(activity => {
                if (this.cursorY > 280) {
                    this.addNewPage();
                    this.cursorY = this.margin;
                    // Mitgliedsname erneut anzeigen bei Seitenwechsel
                    this.pdf.setFont('helvetica', 'bold');
                    this.pdf.setFontSize(12);
                    this.pdf.text(memberName, this.margin, this.cursorY);
                    this.cursorY += 8;
                    this.pdf.setFont('helvetica', 'normal');
                    this.pdf.setFontSize(10);
                }
                
                let activityText = `  • ${activity.name}`;
                if (activity.startTime) {
                    activityText += ` (${activity.startTime}`;
                    if (activity.duration) {
                        activityText += `, ${activity.duration}`;
                    }
                    activityText += ')';
                } else if (activity.duration) {
                    activityText += ` (${activity.duration})`;
                }
                
                this.pdf.text(activityText, this.margin + 5, this.cursorY);
                this.cursorY += 6;
            });

            // Abstand nach Mitglied
            this.cursorY += 3;
        });

        // Falls keine Aktivitäten vorhanden
        if (sortedMembers.length === 0) {
            this.pdf.setFont('helvetica', 'normal');
            this.pdf.setFontSize(11);
            this.pdf.text(this.t('pdfGenerator.noActivities'), this.margin, this.cursorY);
            this.cursorY += 10;
        }
    }

    /**
     * Mannschaftsaufstellung: Titel, Meta-Zeilen (bereits übersetzt) und Spielertabelle.
     * @param {object} options
     * @param {string} [options.title]
     * @param {string[]} [options.introLines]
     * @param {string[][]} options.tableHead - Eine Kopfzeile: [ [col1, col2, …] ]
     * @param {string[][]} options.tableBody
     */
    addTeamLineup({ title, introLines, tableHead, tableBody }) {
        const pdfTitle = title || this.t('pdfGenerator.teamLineupTitle');
        this.cursorY = this.margin;
        this.pdf.setFont('helvetica', 'bold');
        this.pdf.setFontSize(15);
        this.pdf.text(pdfTitle, this.margin, this.cursorY);
        this.cursorY += 9;
        this.pdf.setFont('helvetica', 'normal');
        this.pdf.setFontSize(10);
        const maxW = 210 - this.margin * 2;
        for (const line of introLines || []) {
            const lines = this.pdf.splitTextToSize(String(line), maxW);
            lines.forEach((ln) => {
                this.pdf.text(ln, this.margin, this.cursorY);
                this.cursorY += 5;
            });
        }
        this.cursorY += 3;
        autoTable(this.pdf, {
            startY: this.cursorY,
            margin: { left: this.margin, right: this.margin },
            head: tableHead,
            body: tableBody,
            theme: 'grid',
            styles: { fontSize: 10, cellPadding: 2, overflow: 'linebreak' },
            headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left', fontStyle: 'bold' }
        });
    }

}

export default PDFGenerator;
