<template>
    <div class="match-report-dialog">
        <div class="report-content">
            <div v-if="loading" class="loading">
                <div class="spinner"></div>
                <p>{{ $t('matchReportApi.loading') }}</p>
            </div>

            <div v-else-if="error" class="error">
                <h3>❌ {{ $t('matchReportApi.errorLoading') }}</h3>
                <p>{{ error }}</p>
                <button @click="loadData" class="retry-btn">🔄 {{ $t('matchReportApi.retry') }}</button>
            </div>

            <div v-else-if="meetingData" class="meeting-info">
                <div class="match-header">
                    <h2>{{ formatDate(meetingData.scheduleDate) }} - {{ meetingData.homeTeamname }} : {{ meetingData.guestTeamname }}</h2>
                    <div class="match-details">
                        <p><strong>{{ meetingData.championship }}</strong> · {{ meetingData.league }}<template v-if="meetingData.group && !leagueEqualsGroup"> · {{ meetingData.group }}</template></p>
                    </div>
                </div>

                <div class="nuscore-sections">
                    <div class="section-grid">
                        <button class="section-btn" :class="{ active: activeSection === 'general' }" @click="setActiveSection('general')">
                            <div class="section-icon">ℹ️</div>
                            <span>{{ $t('matchReportApi.general') }}</span>
                        </button>

                        <button class="section-btn" :class="{ active: activeSection === 'homeLineup', certified: isHomeLineupCertified, disabled: !canOpenLineupTab('home') }"
                            @click="setActiveSection('homeLineup')" :disabled="!canOpenLineupTab('home')">
                            <div class="section-icon">👥</div>
                            <span>{{ $t('matchReportApi.homeLineup') }}</span>
                            <span v-if="isHomeLineupCertified" class="certified-badge">✓</span>
                        </button>

                        <button class="section-btn" :class="{ active: activeSection === 'guestLineup', certified: isGuestLineupCertified, disabled: !canOpenLineupTab('guest') }"
                            @click="setActiveSection('guestLineup')" :disabled="!canOpenLineupTab('guest')">
                            <div class="section-icon">👥</div>
                            <span>{{ $t('matchReportApi.guestLineup') }}</span>
                            <span v-if="isGuestLineupCertified" class="certified-badge">✓</span>
                        </button>

                        <button class="section-btn" :class="{ active: activeSection === 'greeting', completed: isGreetingCompleted, disabled: !canOpenNextStages }"
                            @click="setActiveSection('greeting')" :disabled="!canOpenNextStages">
                            <div class="section-icon">👋</div>
                            <span>{{ $t('matchReportApi.greeting') }}</span>
                            <span v-if="isGreetingCompleted" class="completed-badge">✅</span>
                        </button>

                        <button class="section-btn" :class="{ active: activeSection === 'result', disabled: !canOpenResultStage }"
                            @click="setActiveSection('result')" :disabled="!canOpenResultStage">
                            <div class="section-icon">⚽</div>
                            <span>{{ $t('matchReportApi.result') }}</span>
                            <span v-if="isMatchCompleted" class="locked-indicator">🔒</span>
                        </button>

                        <button class="section-btn" :class="{ active: activeSection === 'completion', disabled: !canOpenCompletionStage }"
                            @click="setActiveSection('completion')" :disabled="!canOpenCompletionStage">
                            <div class="section-icon">✅</div>
                            <span>{{ $t('matchReportApi.completion') }}</span>
                        </button>
                    </div>
                </div>

                <div class="section-content">
                    <div v-if="activeSection === 'general'" class="general-content">
                        <div class="match-stats">
                            <div class="team-stats">
                                <div class="home-team">
                                    <h3>{{ meetingData.homeClub }}</h3>
                                    <div class="points">{{ getOverallMatchScore().split(':')[0] }}</div>
                                </div>
                                <div class="vs">{{ $t('matchReportApi.vs') }}</div>
                                <div class="guest-team">
                                    <h3>{{ meetingData.guestClub }}</h3>
                                    <div class="points">{{ getOverallMatchScore().split(':')[1] }}</div>
                                </div>
                            </div>
                        </div>

                        <div class="match-info-grid">
                            <div class="info-item">
                                <label>Startzeit:</label>
                                <div class="time-input-group">
                                    <input 
                                        type="time" 
                                        :value="getFormattedTime(match.startDate)" 
                                        @change="setStartTime($event.target.value)"
                                        class="time-input"
                                    />
                                    <button @click="setCurrentStartTime" class="time-btn" :title="$t('matchReportApi.setCurrentTime')">🕐</button>
                                </div>
                            </div>

                            <div class="info-item">
                                <label>{{ $t('matchReportApi.endTime') }}:</label>
                                <div class="time-input-group">
                                    <input 
                                        type="time" 
                                        :value="getFormattedTime(match.endDate)" 
                                        @change="setEndTime($event.target.value)"
                                        class="time-input"
                                    />
                                    <button @click="setCurrentEndTime" class="time-btn" :title="$t('matchReportApi.setCurrentTime')">🕐</button>
                                </div>
                            </div>

                            <div class="info-item">
                                <label>{{ $t('matchReportApi.status') }}:</label>
                                <span :class="meetingData.isCompleted ? 'completed' : 'pending'">
                                    {{ meetingData.isCompleted ? $t('matchReportApi.completed') : $t('matchReportApi.pending') }}
                                </span>
                            </div>

                            <div class="info-item">
                                <label>{{ $t('matchReportApi.notAppeared') }}:</label>
                                <select 
                                    v-model="teamNotAppeared" 
                                    class="not-appeared-select"
                                    :class="{ 'not-appeared': teamNotAppeared !== null }"
                                >
                                    <option :value="null">{{ $t('matchReportApi.bothTeamsAppeared') }}</option>
                                    <option value="home">{{ $t('matchReportApi.homeTeamNotAppeared', { team: meetingData.homeTeamname || meetingData.homeClub }) }}</option>
                                    <option value="guest">{{ $t('matchReportApi.guestTeamNotAppeared', { team: meetingData.guestTeamname || meetingData.guestClub }) }}</option>
                                </select>
                            </div>

                            <div class="info-item" v-if="(meetingDetails && meetingDetails.playMode) || (meetingData && (meetingData.playMode || meetingData.matchSystem || meetingData.system))">
                                <label>{{ $t('matchReportApi.playSystem') }}:</label>
                                <span>{{ (meetingDetails && meetingDetails.playMode) || meetingData.playMode || meetingData.matchSystem || meetingData.system }}</span>
                            </div>
                        </div>
                    </div>

                    <div v-else-if="activeSection === 'homeLineup'" class="lineup-content">
                        <h3>{{ $t('matchReportApi.homeLineup') }} ({{ meetingData.homeTeamname }})</h3>

                        <!-- PIN-Eingabe für Heimverein -->
                        <div class="pin-section">
                            <h4>{{ $t('matchReportApi.pinInput') }}</h4>
                            <div class="pin-input-group">
                                <label for="homePin">{{ $t('matchReportApi.homePin') }}:</label>
                                <div class="pin-input-wrapper">
                                    <input id="homePin" v-model="homePin" type="password" :class="pinInputClasses('home')"
                                        :disabled="isLineupLocked('home')"
                                        @input="onPinChange('home', $event)" />
                                    <button @click="signLineup('home')" :class="signButtonClasses('home')"
                                        :disabled="!canSignLineup('home')">
                                        {{ signButtonLabel('home') }}
                                    </button>
                                </div>
                                <!-- Fehlermeldung für Mindestspielerzahlen -->
                                <div v-if="getPlayerCountErrorMessage('home')" class="pin-error-message">
                                    {{ getPlayerCountErrorMessage('home') }}
                                </div>
                            </div>
                        </div>

                        <div v-if="meetingDetails && meetingDetails.teamLineupHomePlayers" class="lineup-section">
                            <h4>{{ $t('matchReportApi.selectedPlayers') }}</h4>
                            <div class="players-grid">
                                <div v-for="player in meetingDetails.teamLineupHomePlayers.filter(p => p.isSelected && p.nuLigaPersonId > 0)"
                                    :key="player.nuLigaPersonId" class="player-card selected">
                                    <div class="player-main" @click="togglePlayerSelection(player, 'home')">
                                        <div class="player-name">{{ player.firstname }} {{ player.lastname }}</div>
                                        <div class="player-details">
                                            <span class="player-rank">{{ $t('matchReportApi.rank') }}: {{ player.rank }}</span>
                                            <span class="player-position">
                                                {{ player.positions.join(', ') }}
                                                <span v-if="player.positionDouble" class="double-position"> | D{{
                                                    player.positionDouble }}</span>
                                            </span>
                                        </div>
                                        <div class="player-action">👆 {{ $t('matchReportApi.clickToRemove') }}</div>
                                    </div>
                                    <div class="double-selection">
                                        <button class="double-btn d1-btn"
                                            :class="{ active: player.positionDouble === 1 }"
                                            @click="toggleDoublePosition(player, 'home', 1)"
                                            :disabled="!canSelectDoublePosition(player, 'home', 1)">
                                            D1
                                        </button>
                                        <button class="double-btn d2-btn"
                                            :class="{ active: player.positionDouble === 2 }"
                                            @click="toggleDoublePosition(player, 'home', 2)"
                                            :disabled="!canSelectDoublePosition(player, 'home', 2)">
                                            D2
                                        </button>
                                    </div>
                                </div>
                            </div>

                            <h4>{{ $t('matchReportApi.availablePlayers') }}</h4>
                            <div class="players-grid">
                                <div v-for="player in meetingDetails.teamLineupHomePlayers.filter(p => !p.isSelected && p.nuLigaPersonId > 0)"
                                    :key="player.nuLigaPersonId" class="player-card available clickable">
                                    <div @click="togglePlayerSelection(player, 'home')">
                                        <div class="player-name">{{ player.firstname }} {{ player.lastname }}</div>
                                        <div class="player-details">
                                            <span class="player-rank">{{ $t('matchReportApi.rank') }}: {{ player.rank }}</span>
                                            <span class="player-position">Verfügbar</span>
                                        </div>
                                        <div class="player-action">👆 Klicken zum Hinzufügen</div>
                                    </div>
                                    <div class="double-selection">
                                        <button class="double-btn d1-btn"
                                            :class="{ active: player.positionDouble === 1 }"
                                            @click="toggleDoublePosition(player, 'home', 1)"
                                            :disabled="!canSelectDoublePosition(player, 'home', 1)">
                                            D1
                                        </button>
                                        <button class="double-btn d2-btn"
                                            :class="{ active: player.positionDouble === 2 }"
                                            @click="toggleDoublePosition(player, 'home', 2)"
                                            :disabled="!canSelectDoublePosition(player, 'home', 2)">
                                            D2
                                        </button>
                                    </div>

                                </div>
                            </div>
                        </div>
                        <div v-else class="no-data">
                            <p>{{ $t('matchReportApi.noLineupData') }}</p>
                        </div>
                    </div>

                    <div v-else-if="activeSection === 'guestLineup'" class="lineup-content">
                        <h3>{{ $t('matchReportApi.guestLineup') }} ({{ meetingData.guestTeamname }})</h3>

                        <!-- PIN-Eingabe für Gastverein -->
                        <div class="pin-section">
                            <h4>{{ $t('matchReportApi.pinInput') }}</h4>
                            <div class="pin-input-group">
                                <label for="guestPin">{{ $t('matchReportApi.guestPin') }}:</label>
                                <div class="pin-input-wrapper">
                                    <input id="guestPin" v-model="guestPin" type="password" :class="pinInputClasses('guest')"
                                        autocomplete="new-password" autocapitalize="off" spellcheck="false"
                                        :disabled="isLineupLocked('guest')"
                                        @input="onPinChange('guest', $event)" />
                                    <button @click="signLineup('guest')" :class="signButtonClasses('guest')"
                                        :disabled="!canSignLineup('guest')">
                                        {{ signButtonLabel('guest') }}
                                    </button>
                                </div>
                                <!-- Fehlermeldung für Mindestspielerzahlen -->
                                <div v-if="getPlayerCountErrorMessage('guest')" class="pin-error-message">
                                    {{ getPlayerCountErrorMessage('guest') }}
                                </div>
                            </div>
                        </div>

                        <div v-if="meetingDetails && meetingDetails.teamLineupGuestPlayers" class="lineup-section">
                            <h4>{{ $t('matchReportApi.selectedPlayers') }}</h4>
                            <div class="players-grid">
                                <div v-for="player in meetingDetails.teamLineupGuestPlayers.filter(p => p.isSelected && p.nuLigaPersonId > 0)"
                                    :key="player.nuLigaPersonId" class="player-card selected">
                                    <div class="player-main" @click="togglePlayerSelection(player, 'guest')">
                                        <div class="player-name">{{ player.firstname }} {{ player.lastname }}</div>
                                        <div class="player-details">
                                            <span class="player-rank">{{ $t('matchReportApi.rank') }}: {{ player.rank }}</span>
                                            <span class="player-position">
                                                {{ player.positions.join(', ') }}
                                                <span v-if="player.positionDouble" class="double-position"> | D{{
                                                    player.positionDouble }}</span>
                                            </span>
                                        </div>
                                        <div class="player-action">👆 {{ $t('matchReportApi.clickToRemove') }}</div>
                                    </div>
                                    <div class="double-selection">
                                        <button class="double-btn d1-btn"
                                            :class="{ active: player.positionDouble === 1 }"
                                            @click="toggleDoublePosition(player, 'guest', 1)"
                                            :disabled="!canSelectDoublePosition(player, 'guest', 1)">
                                            D1
                                        </button>
                                        <button class="double-btn d2-btn"
                                            :class="{ active: player.positionDouble === 2 }"
                                            @click="toggleDoublePosition(player, 'guest', 2)"
                                            :disabled="!canSelectDoublePosition(player, 'guest', 2)">
                                            D2
                                        </button>
                                    </div>
                                </div>
                            </div>

                            <h4>{{ $t('matchReportApi.availablePlayers') }}</h4>
                            <div class="players-grid">
                                <div v-for="player in meetingDetails.teamLineupGuestPlayers.filter(p => !p.isSelected && p.nuLigaPersonId > 0)"
                                    :key="player.nuLigaPersonId" class="player-card available clickable">
                                    <div @click="togglePlayerSelection(player, 'guest')">
                                        <div class="player-name">{{ player.firstname }} {{ player.lastname }}</div>
                                        <div class="player-details">
                                            <span class="player-rank">{{ $t('matchReportApi.rank') }}: {{ player.rank }}</span>
                                            <span class="player-position">Verfügbar</span>
                                        </div>
                                        <div class="player-action">👆 Klicken zum Hinzufügen</div>
                                    </div>
                                    <div class="double-selection">
                                        <button class="double-btn d1-btn"
                                            :class="{ active: player.positionDouble === 1 }"
                                            @click="toggleDoublePosition(player, 'guest', 1)"
                                            :disabled="!canSelectDoublePosition(player, 'guest', 1)">
                                            D1
                                        </button>
                                        <button class="double-btn d2-btn"
                                            :class="{ active: player.positionDouble === 2 }"
                                            @click="toggleDoublePosition(player, 'guest', 2)"
                                            :disabled="!canSelectDoublePosition(player, 'guest', 2)">
                                            D2
                                        </button>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div v-else class="no-data">
                            <p>{{ $t('matchReportApi.noLineupData') }}</p>
                        </div>
                    </div>

                    <div v-else-if="activeSection === 'greeting'" class="greeting-content">
                        <div class="greeting-header">
                            <h3>Begrüßung</h3>
                            <button 
                                @click="toggleGreetingCompleted()" 
                                class="completion-toggle-btn"
                                :class="{ 'completed': isGreetingCompleted }"
                            >
                                {{ isGreetingCompleted ? '✅ Abgeschlossen' : '⚪ Abgeschlossen' }}
                            </button>
                        </div>
                        <div class="greeting-box" v-html="greetingRendered"></div>
                    </div>

                    <div v-else-if="activeSection === 'result'" class="result-content">
                        <div class="result-header">
                            <div class="time-display">
                                <div class="time-row">
                                    <strong>Startzeit:</strong>
                                    <span>{{ formatTime(match.startDate) }}</span>
                                    <button @click="setCurrentStartTime()" class="time-btn-small" :disabled="isMatchCompleted">🕐 jetzt setzen</button>
                                </div>
                            </div>
                        </div>
                        
                        <!-- Warnung bei abgeschlossenem Match -->
                        <div v-if="isMatchCompleted" class="completion-warning">
                            <div class="warning-icon">🔒</div>
                            <div class="warning-text">
                                <strong>Spielbericht bereits abgesendet</strong><br>
                                Diese Ergebniserfassung kann nicht mehr bearbeitet werden.
                            </div>
                        </div>
                        
                        <!-- Spielstand oben -->
                        <div class="score-summary">
                            <div class="score-display">
                                <span class="score-label">Spielstand:</span>
                                <span class="score-value">{{ getOverallScore() }}</span>
                            </div>
                        </div>
                        
                        <table class="result-table">
                            <thead>
                                <tr>
                                    <th>#</th>
                                    <th>Heim</th>
                                    <th>Gast</th>
                                    <th>Satz 1</th>
                                    <th>Satz 2</th>
                                    <th>Satz 3</th>
                                    <th>Satz 4</th>
                                    <th>Satz 5</th>
                                    <th>Status</th>
                                    <th>Ergebnis</th>
                                </tr>
                            </thead>
                            <tbody>
                                <template v-for="(m, idx) in results" :key="idx">
                                    <tr>
                                        <td>{{ idx + 1 }}</td>
                                        <td>{{ m.homeName }}</td>
                                        <td>{{ m.guestName }}</td>
                                        <td v-for="(s, sIdx) in m.sets" :key="sIdx" class="set-cell">
                                            <div class="set-input-wrapper">
                                                <input 
                                                    class="set-input" 
                                                    :class="{ 'gap-warning': shouldHighlightSetInput(idx, sIdx), 'keyboard-open': isSetKeyboardOpen(idx, sIdx) }"
                                                    v-model="m.sets[sIdx]" 
                                                    placeholder=":" 
                                                    :readonly="true"
                                                    :disabled="isSetInputDisabled(idx, sIdx)"
                                                    @click="openSetKeyboard(idx, sIdx)"
                                                />
                                            </div>
                                        </td>
                                        <td class="state-cell">
                                            <div class="state-content">
                                                <button v-if="!m.completed" class="state-btn" @click="completeMatch(idx)" title="Match abschließen">✔</button>
                                                <button v-else class="state-btn" @click="reopenMatch(idx)" title="Match wieder öffnen">✎</button>
                                                <div class="set-ratio">{{ getSetRatio(m) }}</div>
                                            </div>
                                        </td>
                                        <td class="result-cell">
                                            <div class="match-result">{{ getMatchResult(m) }}</div>
                                        </td>
                                    </tr>
                                    <!-- Fehlermeldung für diese Match-Zeile -->
                                    <tr v-if="getMatchError(idx)" class="error-row">
                                        <td colspan="10" class="error-cell">
                                            <div class="error-message">{{ getMatchError(idx) }}</div>
                                        </td>
                                    </tr>
                                </template>
                            </tbody>
                        </table>
                        
                        <!-- Auto-Fill Button -->
                        <div class="autofill-section">
                            <button @click="autoFillEmptyMatches()" class="autofill-btn" :disabled="isMatchCompleted">
                                📝 Auto-ausfüllen: Leere Positionen mit 3:0 automatisch ausfüllen
                            </button>
                        </div>

                        <!-- Spielstand unten -->
                        <div class="score-summary">
                            <div class="score-display">
                                <span class="score-label">Spielstand:</span>
                                <span class="score-value">{{ getOverallScore() }}</span>
                            </div>
                        </div>

                        <!-- Endzeit Sektion -->
                        <div class="endtime-section">
                            <div class="time-display">
                                <div class="time-row">
                                    <strong>Endzeit:</strong>
                                    <span>{{ formatTime(match.endDate) }}</span>
                                    <button @click="setEndTimeAndNavigate()" class="time-btn-small" :disabled="isMatchCompleted">🕐 jetzt setzen</button>
                                </div>
                            </div>
                        </div>

                        <!-- Schwebende Tastatur für Satzeingabe (unterdrückt System-Tastatur) -->
                        <div v-if="editingSetCell" class="set-keyboard-overlay" @click.self="closeSetKeyboard">
                            <div class="set-keyboard" @click.stop>
                                <div class="set-keyboard-value" :class="{ 'placeholder': !editingSetValue }">
                                    {{ editingSetValue || 'Satz z.B. 11:9' }}
                                </div>
                                <div class="set-keyboard-keys">
                                    <!-- 1 2 3 -->
                                    <button type="button" class="set-key" @click="setKeyboardKey('1')">1</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('2')">2</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('3')">3</button>
                                    <!-- 4 5 6 -->
                                    <button type="button" class="set-key" @click="setKeyboardKey('4')">4</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('5')">5</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('6')">6</button>
                                    <!-- 7 8 9 -->
                                    <button type="button" class="set-key" @click="setKeyboardKey('7')">7</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('8')">8</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('9')">9</button>
                                    <!-- : 0 - -->
                                    <button type="button" class="set-key" @click="setKeyboardKey(':')">:</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('0')">0</button>
                                    <button type="button" class="set-key" @click="setKeyboardKey('-')">−</button>
                                    <!-- <- C OK -->
                                    <button type="button" class="set-key set-key-backspace" @click="setKeyboardBackspace">⌫</button>
                                    <button type="button" class="set-key set-key-clear" @click="setKeyboardClear">C</button>
                                    <button type="button" class="set-key set-key-ok" @click="setKeyboardOk">OK</button>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div v-else-if="activeSection === 'completion'" class="completion-content">
                        <!-- Aufstellungen -->
                        <div class="lineups-summary">
                            <div class="lineup-team">
                                <h4>{{ meetingData.homeTeamname }}</h4>
                                <div class="einzel-section">
                                    <h5>Einzel</h5>
                                    <div v-for="(player, idx) in getHomeSinglePlayers()" :key="idx" class="player-row">
                                        {{ idx + 1 }}: {{ player }}
                                    </div>
                                </div>
                                <div class="doppel-section">
                                    <h5>Doppel</h5>
                                    <div v-for="(pair, idx) in getHomeDoublePairs()" :key="idx" class="pair-row">
                                        D{{ idx + 1 }}: {{ pair }}
                                    </div>
                                </div>
                            </div>
                            
                            <div class="team-divider">vs</div>
                            
                            <div class="lineup-team">
                                <h4>{{ meetingData.guestTeamname }}</h4>
                                <div class="einzel-section">
                                    <h5>Einzel</h5>
                                    <div v-for="(player, idx) in getGuestSinglePlayers()" :key="idx" class="player-row">
                                        {{ idx + 1 }}: {{ player }}
                                    </div>
                                </div>
                                <div class="doppel-section">
                                    <h5>Doppel</h5>
                                    <div v-for="(pair, idx) in getGuestDoublePairs()" :key="idx" class="pair-row">
                                        D{{ idx + 1 }}: {{ pair }}
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Endergebnis -->
                        <div class="final-score">
                            <h3>Endergebnis</h3>
                            <div class="score-summary large">
                                <div class="score-display">
                                    <span class="score-label">Spielstand:</span>
                                    <span class="score-value final">{{ getOverallScore() }}</span>
                                </div>
                            </div>
                        </div>

                        <!-- Zeitangaben -->
                        <div class="time-summary">
                            <div class="time-display">
                                <label>Startzeit:</label>
                                <span class="time-value">{{ getFormattedTime(match.startDate) || 'nicht gesetzt' }}</span>
                            </div>
                            
                <div class="time-input-group">
                    <label>Endzeit:</label>
                    <input
                        type="time"
                        :value="getFormattedTime(match.endDate)"
                        @change="setEndTime($event.target.value)"
                        class="time-input"
                        :disabled="isMatchCompleted"
                    />
                    <button 
                        @click="setCurrentEndTime" 
                        class="time-btn" 
                        title="Aktuelle Zeit setzen"
                        :disabled="isMatchCompleted"
                    >🕐</button>
                </div>
                        </div>

                        <!-- Protest-Eingabe -->
                        <div class="protest-section">
                            <label for="protestInput">Protest:</label>
                            <textarea
                                id="protestInput"
                                v-model="protestText"
                                placeholder="Protestgrund eingeben..."
                                class="protest-input"
                                :disabled="isMatchCompleted"
                            ></textarea>
                        </div>

                        <!-- PIN-Eingaben -->
                        <div class="final-pins">
                            <div class="pin-group">
                                <label for="finalHomePin">PIN Heimverein:</label>
                                <input
                                    id="finalHomePin"
                                    v-model="finalHomePin"
                                    type="password"
                                    class="pin-input"
                                    placeholder="PIN eingeben"
                                    :disabled="isMatchCompleted || teamNotAppeared === 'home'"
                                />
                                <span v-if="teamNotAppeared === 'home'" class="pin-not-required">(nicht erforderlich - Mannschaft nicht angetreten)</span>
                            </div>

                            <div class="pin-group">
                                <label for="finalGuestPin">PIN Gastverein:</label>
                                <input
                                    id="finalGuestPin"
                                    v-model="finalGuestPin"
                                    type="password"
                                    class="pin-input"
                                    placeholder="PIN eingeben"
                                    :disabled="isMatchCompleted || teamNotAppeared === 'guest'"
                                />
                                <span v-if="teamNotAppeared === 'guest'" class="pin-not-required">(nicht erforderlich - Mannschaft nicht angetreten)</span>
                            </div>
                        </div>

            <!-- Absenden-Button -->
            <div class="submit-section">
                <button 
                    @click="submitMatchReport" 
                    class="btn-primary submit-btn"
                    :disabled="isSubmitDisabled"
                    :class="{ 'disabled': isSubmitDisabled }"
                >
                    {{ getSubmitButtonText() }}
                </button>
                
                <!-- Warnung wenn Match abgeschlossen -->
                <div v-if="isMatchCompleted" class="completion-notice">
                    ⚠️ Dieser Spielbericht wurde bereits abgesendet. Keine weiteren Änderungen möglich.
                </div>
                
                <!-- Warnung wenn Match-Ergebnisse fehlerhaft sind -->
                <div v-else-if="!areAllMatchResultsValid()" class="validation-notice">
                    <span v-if="getPlayThrough() && getPlayThrough().toUpperCase().includes('ALLGAMES') && canBothTeamsPlayAllGames()">
                        ❌ Der Spielbericht kann nicht abgesendet werden. Es müssen alle Spiele abgeschlossen sein.
                        <br><strong>Bitte schließen Sie alle {{ results.filter(match => !match.completed).length }} offenen Spiele ab!</strong>
                    </span>
                    <span v-else-if="getPlayThrough() && getPlayThrough().toUpperCase().includes('ALLGAMES') && !canBothTeamsPlayAllGames()">
                        ℹ️ ALLGAMES-Modus aktiv, aber beide Mannschaften haben nicht genügend Spieler für alle Spiele.
                        <br><strong>Das Absenden ist trotzdem möglich. Abgeschlossene Spiele werden übertragen.</strong>
                    </span>
                    <span v-else>
                        ❌ Der Spielbericht kann nicht abgesendet werden. Es gibt noch Fehler in den Match-Ergebnissen.
                        <br><strong>Bitte überprüfen Sie die Ergebniserfassung!</strong>
                    </span>
                </div>
                
                <!-- Warnung wenn Zeiten fehlerhaft sind -->
                <div v-else-if="!areStartAndEndTimesValid()" class="validation-notice">
                    ❌ Der Spielbericht kann nicht abgesendet werden. Start- oder Endzeit sind nicht festgelegt.
                    <br><strong>Bitte legen Sie beide Zeiten fest!</strong>
                </div>
            </div>
                    </div>
                </div>

                <div class="actions">
                    <button @click="openNuscorePage" class="nuscore-btn">
                        📊 Vollständigen Spielberichtsbogen öffnen
                    </button>
                </div>
            </div>
        </div>

        <div class="draft-status-bar" :class="`state-${draftStatusState}`">
            <span class="draft-status-dot" aria-hidden="true"></span>
            <span class="draft-status-text">{{ draftStatusText }}</span>
        </div>

        <!-- PIN-Modal für zertifizierte Aufstellungen -->
        <div v-if="showPinModal" class="pin-modal-overlay" @click="closePinModal">
            <div class="pin-modal" @click.stop>
                <div class="pin-modal-header">
                    <h3>PIN-Eingabe erforderlich</h3>
                    <button @click="closePinModal" class="pin-modal-close">&times;</button>
                </div>
                <div class="pin-modal-body">
                    <p>Diese Aufstellung ist zertifiziert. Bitte geben Sie die passende PIN ein, um sie wieder zu bearbeiten.</p>
                    
                    <div class="pin-modal-inputs">
                        <div v-if="pinModalRequiresHomePin()" class="pin-input-group">
                            <label for="modalHomePin">PIN Heimmannschaft:</label>
                            <input 
                                id="modalHomePin"
                                v-model="pinModalHomePin"
                                type="password" 
                                class="pin-input"
                                :placeholder="meetingDetails && meetingDetails.homePin ? 'Echte Heim-PIN eingeben' : 'PIN eingeben'"
                                @keyup.enter="submitPinModal"
                            />
                            <small v-if="originalHomePin" class="pin-hint">
                                💡 Die ursprünglich verwendete Heim-PIN ist: {{ originalHomePin }}
                            </small>
                        </div>
                        
                        <div v-if="pinModalRequiresGuestPin()" class="pin-input-group">
                            <label for="modalGuestPin">PIN Gastmannschaft:</label>
                            <input 
                                id="modalGuestPin"
                                v-model="pinModalGuestPin"
                                type="password" 
                                class="pin-input"
                                placeholder="PIN eingeben"
                                @keyup.enter="submitPinModal"
                            />
                            <small v-if="originalGuestPin && meetingDetails && meetingDetails.guestPin" class="pin-hint">
                                💡 Die ursprünglich verwendete Gast-PIN ist: {{ originalGuestPin }}
                            </small>
                        </div>
                    </div>
                    
                    <div v-if="pinModalError" class="pin-modal-error">
                        {{ pinModalError }}
                    </div>
                </div>
                <div class="pin-modal-footer">
                    <button @click="closePinModal" class="btn-secondary">Abbrechen</button>
                    <button @click="submitPinModal" class="btn-primary">Bestätigen</button>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import CryptoJS from 'crypto-js';
import apiClient, { backendBaseUrl } from '../apiClient';
import { onMatchReportSubmitted, offMatchReportSubmitted } from '../services/socketService.js';

export default {
    name: 'MatchReportDialog',
    props: {
        match: {
            type: Object,
            required: true
        }
    },
    data() {
        return {
            loading: true,
            error: null,
            meetingData: null,
            meetingDetails: null,
            activeSection: 'general',
            homePin: '',
            guestPin: '',
            pinFeedback: {
                home: '',
                guest: ''
            },
            signingFeedback: {
                home: '',
                guest: ''
            },
            pinFeedbackTimers: {
                home: null,
                guest: null
            },
            signingFeedbackTimers: {
                home: null,
                guest: null
            },
            initialCompletionState: false,
            submitSucceeded: false,
            isHomeLineupCertified: false,
            isGuestLineupCertified: false,
            isGreetingCompleted: false,
            // Nicht angetreten: 'both', 'home', 'guest', null
            teamNotAppeared: null,
            originalHomePin: '',
            originalGuestPin: '',
            showPinModal: false,
            pinModalTeam: null,
            pinModalHomePin: '',
            pinModalGuestPin: '',
            pinModalError: '',
            // Ergebnisse für Ergebniserfassung
            results: [],
            // Fehlermeldungen für Satzeingaben
            errors: [],
            // Aktive Zelle der schwebenden Satz-Tastatur: { matchIndex, setIndex } oder null
            editingSetCell: null,
            broadcastDraftTimer: null,
            draftPersistTimer: null,
            draftSyncTimer: null,
            meetingDetailsPollInterval: null,
            isMeetingDetailsPolling: false,
            lastMeetingDetailsSignature: '',
            isDraftSyncing: false,
            lastDraftSyncError: '',
            draftLastSavedAt: null,
            draftLastSyncedAt: null,
            // Abschluss-Felder
            protestText: '',
            finalHomePin: '',
            finalGuestPin: '',
            // Definitionen der Spielsysteme als Matrizen (Reihenfolge der Begegnungen)
            // A = Heim (A1..), B = Gast (B1..), D = Doppel (DAx, DBx)
            playModeMatrices: {
                'paarkreuz-system': [
                    'DA1 – DB2', 'DA2 – DB1', 'DA3 – DB3',
                    'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3', 'A5 – B6',
                    'A6 – B5', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A5 – B5', 'A6 – B6', 'DA1 – DB1'
                ],
                'bundessystem': [
                    'DA1 – DB1', 'DA2 – DB2', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4'
                ],
                'werner-scheffler-system': [
                    'DA1 – DB1', 'DA2 – DB2', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A3 – B1', 'A1 – B3', 'A2 – B4', 'A4 – B2'
                ],
                'braunschweiger system': {
                    // Dynamische Auswahl je nach Spielerzahlen
                    matrices: {
                        // 4 vs 4 Spieler
                        '4-4': ['DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3'],
                        // 4 vs 3 Spieler  
                        '4-3': ['DA1 – DB1', 'A3 – B3', 'A1 – B2', 'A2 – B1', 'A4 – B2', 'A1 – B1', 'A4 – B3', 'A2 – B2', 'A1 – B3', 'A3 – B1'],
                        // 3 vs 4 Spieler
                        '3-4': ['DA1 – DB1', 'A3 – B3', 'A2 – B1', 'A1 – B2', 'A2 – B4', 'A1 – B1', 'A3 – B4', 'A2 – B2', 'A3 – B1', 'A1 – B3'],
                        // 3 vs 3 Spieler
                        '3-3': ['DA1 – DB1', 'A1 – B2', 'A2 – B1', 'A3 – B2', 'A2 – B3', 'A1 – B1', 'A3 – B3', 'A2 – B2', 'A3 – B1', 'A1 – B3']
                    },
                    // Fallback für unbekannte Kombination
                    default: ['DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3']
                },
                'modifiziertes swaythling-cup-system': [
                    'A1 – B2', 'A2 – B1', 'A3 – B3', 'DA1 – DB1', 'A1 – B1', 'A3 – B2', 'A2 – B3'
                ],
                'corbillon-cup-system': [
                    'A1 – B1', 'A2 – B2', 'DA1 – DB1', 'A1 – B2', 'A2 – B1'
                ]
            }
        };
    },
    computed: {
        greetingRendered() {
            const fallback = `Wir begrüßen unsere Gäste herzlich zum Spiel zwischen {home} und {guest}.
Unsere Gäste spielen mit
{guestplayers}.
Wir spielen mit 
{homeplayers}.
Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begrüßen Euch mit einem einfachen "Gut - Sport".`;
            const txt = (this.clubSettings && this.clubSettings.greetingText ? this.clubSettings.greetingText : fallback);
            const homePlayersOnly = this.formatPlayers('home');
            const guestPlayersOnly = this.formatPlayers('guest');
            const homeDoubles = this.formatDoubles('home');
            const guestDoubles = this.formatDoubles('guest');
            const homePlayers = homeDoubles ? `${homePlayersOnly}\nIn den Doppeln: ${homeDoubles}` : homePlayersOnly;
            const guestPlayers = guestDoubles ? `${guestPlayersOnly}\nIn den Doppeln: ${guestDoubles}` : guestPlayersOnly;
            const homeName = (this.meetingData && this.meetingData.homeTeamname) ? this.meetingData.homeTeamname : '';
            const guestName = (this.meetingData && this.meetingData.guestTeamname) ? this.meetingData.guestTeamname : '';
            return txt
                .replaceAll('{home}', homeName)
                .replaceAll('{guest}', guestName)
                .replaceAll('{homeplayers}', homePlayers)
                .replaceAll('{guestplayers}', guestPlayers);
        },
        leagueEqualsGroup() {
            if (!this.meetingData) return false;
            const norm = (s) => (s || '')
                .toString()
                .normalize('NFKC')
                .toLowerCase()
                .replace(/[\s._\-\/]+/g, '')
                .trim();
            return norm(this.meetingData.league) === norm(this.meetingData.group);
        },
        editingSetValue() {
            if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return '';
            const sets = this.results[this.editingSetCell.matchIndex].sets || [];
            return sets[this.editingSetCell.setIndex] || '';
        },
        canOpenNextStages() {
            // Wenn das Match bereits abgeschlossen ist, dürfen keine Änderungen mehr gemacht werden
            if (this.isMatchCompleted) {
                return false;
            }
            // WO-Fall: keine Ergebniserfassung, Abschluss darf aber direkt geöffnet werden
            if (this.teamNotAppeared !== null) {
                return true;
            }
            // Wenn eine Mannschaft nicht angetreten ist, muss die andere Mannschaft ihre Aufstellung signieren
            // Beide Mannschaften angetreten -> beide müssen Aufstellung signieren
            return this.isHomeLineupCertified && this.isGuestLineupCertified;
        },
        canOpenResultStage() {
            if (this.teamNotAppeared !== null) {
                return false;
            }
            return this.areBothLineupsCertified();
        },
        canOpenCompletionStage() {
            if (this.isMatchCompleted) {
                return false;
            }
            if (this.teamNotAppeared !== null) {
                return true;
            }
            return this.canOpenNextStages;
        },
        currentPlayMode() {
            return (this.meetingDetails && this.meetingDetails.playMode) || (this.meetingData && this.meetingData.playMode) || '';
        },
        currentPlayModeMatrix() {
            const key = (this.currentPlayMode || '').toLowerCase();
            const matrixConfig = this.playModeMatrices[key];
            
            // Spezielle Behandlung für Braunschweiger System
            if (matrixConfig && typeof matrixConfig === 'object' && matrixConfig.matrices) {
                const serverMatrix = this.getBraunschweigerServerMatrix();
                if (Array.isArray(serverMatrix) && serverMatrix.length > 0) {
                    console.log('🎯 Braunschweiger System: verwende Server-Matrix', serverMatrix);
                    return serverMatrix;
                }

                const homePlayerCount = this.getEffectivePlayerCount('home');
                const guestPlayerCount = this.getEffectivePlayerCount('guest');
                
                // Erstelle Key basierend auf Spielerzahlen (z.B. "3-4", "4-4")
                const playerCountKey = `${homePlayerCount}-${guestPlayerCount}`;
                
                console.log(`🎯 Braunschweiger System: ${homePlayerCount} vs ${guestPlayerCount} → Key: ${playerCountKey}`);
                this.logBraunschweigerDebugSnapshot(`Matrix-Auswahl ${playerCountKey}`);
                
                // Verwende spezifische Matrix oder Fallback
                return matrixConfig.matrices[playerCountKey] || matrixConfig.default || [];
            }
            
            // Standard-Verhalten für andere Systeme
            return matrixConfig || [];
        },

        // Prüfe ob das Match bereits abgeschlossen ist
        isMatchCompleted() {
            return this.submitSucceeded || this.initialCompletionState === true;
        },
        isSubmitDisabled() {
            if (this.isMatchCompleted) {
                return true;
            }

            if (this.teamNotAppeared !== null) {
                return false;
            }

            return !this.areAllMatchResultsValid() || !this.areStartAndEndTimesValid();
        },
        draftStatusState() {
            if (this.isDraftSyncing) {
                return 'syncing';
            }
            if (this.lastDraftSyncError) {
                return 'fallback';
            }
            if (this.draftLastSavedAt) {
                return 'saved';
            }
            return 'idle';
        },
        draftStatusText() {
            if (this.draftStatusState === 'syncing') {
                return 'Synchronisiere Entwurf...';
            }
            if (this.draftStatusState === 'fallback') {
                return 'Offline-Fallback aktiv (lokal gespeichert)';
            }
            if (this.draftStatusState === 'saved') {
                return 'Zwischengespeichert';
            }
            return 'Bereit';
        }
    },
    async mounted() {
        await this.loadData();
        this.initializeResults();
        this.initializeFinalPins();
        this.restoreLocalDraft();
        this.startMeetingDetailsPolling();
        this._matchReportSubmittedHandler = (payload) => {
            if (!payload?.matchCode || !this.match?.code || String(payload.matchCode) !== String(this.match.code)) {
                return;
            }
            if (payload.matchData && this.meetingDetails) {
                this.applyReceivedMatchData(payload.matchData);
            } else {
                this.loadData();
            }
        };
        onMatchReportSubmitted(this._matchReportSubmittedHandler);
    },
    beforeUnmount() {
        if (this._matchReportSubmittedHandler) {
            offMatchReportSubmitted(this._matchReportSubmittedHandler);
        }
        this.stopMeetingDetailsPolling();
        if (this.broadcastDraftTimer) {
            clearTimeout(this.broadcastDraftTimer);
        }
        if (this.draftPersistTimer) {
            clearTimeout(this.draftPersistTimer);
        }
        if (this.draftSyncTimer) {
            clearTimeout(this.draftSyncTimer);
        }
        ['home', 'guest'].forEach(team => {
            if (this.pinFeedbackTimers[team]) {
                clearTimeout(this.pinFeedbackTimers[team]);
            }
            if (this.signingFeedbackTimers[team]) {
                clearTimeout(this.signingFeedbackTimers[team]);
            }
        });
    },
    watch: {
        teamNotAppeared(newValue, oldValue) {
            if (newValue === oldValue) {
                return;
            }

            if (this.meetingData) {
                if (newValue === null) {
                    // Entferne das wo-Flag beim Zurücksetzen
                    this.meetingData.wo = null;
                } else {
                    // Wende die "Nicht angetreten"-Logik an
                    this.applyTeamNotAppeared();
                }
            }

            if (newValue === 'home') {
                this.setLineupCertificationState('home', false);
                this.homePin = '';
                this.finalHomePin = '';
                this.activeSection = 'completion';
                return;
            }

            if (newValue === 'guest') {
                this.setLineupCertificationState('guest', false);
                this.guestPin = '';
                this.finalGuestPin = '';
                this.activeSection = 'completion';
                return;
            }

            if (newValue === null && this.activeSection === 'completion' && !this.canOpenNextStages) {
                this.activeSection = 'general';
            }

            this.persistLocalDraftDebounced();
            this.broadcastDraftDebounced();
        },
        results: {
            handler() {
                this.persistLocalDraftDebounced();
            },
            deep: true
        },
        meetingDetails: {
            handler() {
                this.persistLocalDraftDebounced();
            },
            deep: true
        },
        homePin() {
            this.persistLocalDraftDebounced();
        },
        guestPin() {
            this.persistLocalDraftDebounced();
        },
        finalHomePin() {
            this.persistLocalDraftDebounced();
        },
        finalGuestPin() {
            this.persistLocalDraftDebounced();
        },
        protestText() {
            this.persistLocalDraftDebounced();
        },
        activeSection() {
            this.persistLocalDraftDebounced();
        }
    },
    methods: {
        startMeetingDetailsPolling() {
            this.stopMeetingDetailsPolling();
            this.meetingDetailsPollInterval = setInterval(() => {
                this.pollLatestMeetingDetails();
            }, 15000);
        },
        stopMeetingDetailsPolling() {
            if (this.meetingDetailsPollInterval) {
                clearInterval(this.meetingDetailsPollInterval);
                this.meetingDetailsPollInterval = null;
            }
        },
        buildMeetingDetailsSignature(details) {
            if (!details || typeof details !== 'object') {
                return '';
            }

            const normalizePlayer = (player) => ({
                nuLigaPersonId: player?.nuLigaPersonId ?? null,
                firstName: player?.firstName ?? player?.firstname ?? '',
                lastName: player?.lastName ?? player?.lastname ?? '',
                isSelected: Boolean(player?.isSelected),
                rank: player?.rank ?? null,
                positionSingle: player?.positionSingle ?? null,
                positionDouble: player?.positionDouble ?? null,
                positions: Array.isArray(player?.positions) ? [...player.positions] : []
            });

            const normalizeMatch = (match) => ({
                name: match?.name ?? '',
                homePlayer: match?.homePlayer ?? '',
                guestPlayer: match?.guestPlayer ?? '',
                matchesA: match?.matchesA ?? null,
                matchesB: match?.matchesB ?? null,
                set1A: match?.set1A ?? null,
                set1B: match?.set1B ?? null,
                set2A: match?.set2A ?? null,
                set2B: match?.set2B ?? null,
                set3A: match?.set3A ?? null,
                set3B: match?.set3B ?? null,
                set4A: match?.set4A ?? null,
                set4B: match?.set4B ?? null,
                set5A: match?.set5A ?? null,
                set5B: match?.set5B ?? null
            });

            return JSON.stringify({
                isCompleted: details.isCompleted ?? null,
                wo: details.wo ?? null,
                startDate: details.startDate ?? null,
                endDate: details.endDate ?? null,
                homePin: details.homePin ?? null,
                guestPin: details.guestPin ?? null,
                signature: details.signature ?? null,
                teamLineupHomePlayers: Array.isArray(details.teamLineupHomePlayers)
                    ? details.teamLineupHomePlayers.map(normalizePlayer)
                    : [],
                teamLineupGuestPlayers: Array.isArray(details.teamLineupGuestPlayers)
                    ? details.teamLineupGuestPlayers.map(normalizePlayer)
                    : [],
                matches: Array.isArray(details.matches) ? details.matches.map(normalizeMatch) : []
            });
        },
        async pollLatestMeetingDetails() {
            if (this.loading || this.isMeetingDetailsPolling) {
                return;
            }

            const meetingUuid = this.meetingData?.nuLigaMeetingUuid;
            if (!meetingUuid) {
                return;
            }

            this.isMeetingDetailsPolling = true;
            try {
                const response = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${meetingUuid}`);
                if (!response.ok) {
                    return;
                }

                const latestMeetingDetails = await response.json();
                const latestSignature = this.buildMeetingDetailsSignature(latestMeetingDetails);

                if (latestSignature === this.lastMeetingDetailsSignature) {
                    return;
                }

                this.lastMeetingDetailsSignature = latestSignature;
                this.meetingDetails = latestMeetingDetails;

                if (latestMeetingDetails.startDate != null && this.meetingData) {
                    this.meetingData.startDate = latestMeetingDetails.startDate;
                }
                if (latestMeetingDetails.endDate != null && this.meetingData) {
                    this.meetingData.endDate = latestMeetingDetails.endDate;
                }

                this.initialCompletionState = Boolean(
                    ((typeof latestMeetingDetails?.isCompleted === 'boolean' && latestMeetingDetails.isCompleted) &&
                        this.hasReleaseSignatureForCompletion(latestMeetingDetails)) ||
                    ((typeof this.meetingData?.isCompleted === 'boolean' && this.meetingData.isCompleted) &&
                        this.hasReleaseSignatureForCompletion(this.meetingData))
                );

                this.populateResultsFromMeetingDetails();
                this.applyLineupCertificationFromMeetingDetails();
            } catch (error) {
                console.warn('⚠️ Polling der Meeting-Details fehlgeschlagen:', error);
            } finally {
                this.isMeetingDetailsPolling = false;
            }
        },
        logBraunschweigerDebugSnapshot(context, payload = this.meetingDetails) {
            if (!payload || typeof payload !== 'object') {
                console.log(`[Braunschweiger Debug] ${context}: keine Daten`);
                return;
            }

            const summarizeTeam = (teamKey) => {
                const players = Array.isArray(payload[teamKey]) ? payload[teamKey] : [];
                return players.map(player => ({
                    id: player?.nuLigaPersonId ?? null,
                    name: [player?.firstname || player?.firstName || '', player?.lastname || player?.lastName || ''].filter(Boolean).join(' ').trim(),
                    selected: Boolean(player?.isSelected),
                    positionSingle: player?.positionSingle ?? null,
                    positionDouble: player?.positionDouble ?? null,
                    positions: Array.isArray(player?.positions) ? [...player.positions] : []
                }));
            };

            const matches = Array.isArray(payload.matches)
                ? payload.matches.slice(0, 10).map((match, index) => ({
                    index: index + 1,
                    homePlayer: match?.homePlayer ?? '',
                    guestPlayer: match?.guestPlayer ?? '',
                    matchNumber: match?.matchNumber ?? null
                }))
                : [];

            console.log(`[Braunschweiger Debug] ${context}`, {
                playMode: payload.playMode || this.meetingData?.playMode || this.meetingData?.matchSystem || this.meetingData?.system || null,
                homePlayers: summarizeTeam('teamLineupHomePlayers'),
                guestPlayers: summarizeTeam('teamLineupGuestPlayers'),
                matches
            });
        },

        getFriendlySubmitErrorMessage(message) {
            const normalized = (message || '').toString();

            if (normalized.includes('Meeting wurde bereits freigegeben')) {
                return 'Der Spielbericht ist in nuScore bereits freigegeben.\n\nDie dort gespeicherten Daten sind offenbar nicht vollständig und können aus dieser Ansicht nicht mehr zuverlässig überschrieben werden.\n\nBitte den Spielbericht in nuScore bzw. durch eine Person mit den nötigen Rechten prüfen und dort korrigieren lassen.';
            }

            return normalized || 'Fehler beim Absenden des Spielberichts.';
        },

        hasReleaseSignatureForCompletion(source) {
            if (!source) {
                return false;
            }

            const signature = source.signature || {};
            const fallbackWo = this.teamNotAppeared === 'home'
                ? 'A'
                : (this.teamNotAppeared === 'guest' ? 'B' : null);
            const wo = source.wo ?? fallbackWo;

            const hasHomeRelease = typeof signature.releaseSignatureHome === 'string' && signature.releaseSignatureHome.trim() !== '';
            const hasGuestRelease = typeof signature.releaseSignatureGuest === 'string' && signature.releaseSignatureGuest.trim() !== '';

            if (wo === 'A') {
                return hasGuestRelease;
            }
            if (wo === 'B') {
                return hasHomeRelease;
            }

            return hasHomeRelease && hasGuestRelease;
        },

        // Effektive Spieleranzahl (berücksichtigt Braunschweiger-Regel)
        getEffectivePlayerCount(team) {
            const actualCount = this.getSelectedPlayerCount(team);
            const playMode = this.getPlayMode();
            
            // Spezieller Fall für Braunschweiger System: 2er-Mannschaften werden als 3er-Mannschaften gewertet
            if (playMode && playMode.toLowerCase().includes('braunschweiger') && actualCount === 2) {
                console.log(`🎯 Braunschweiger System: ${team} hat ${actualCount} Spieler, wird als 3er-Mannschaft gewertet`);
                return 3;
            }
            
            return actualCount;
        },

        // Prüfe ob beide Mannschaften genügend Spieler für alle Spiele haben
        canBothTeamsPlayAllGames() {
            const playMode = this.getPlayMode();
            const homePlayerCount = this.getSelectedPlayerCount('home');
            const guestPlayerCount = this.getSelectedPlayerCount('guest');
            
            console.log(`🔍 Prüfe Spielberechtigung: ${playMode}, Heim: ${homePlayerCount}, Gast: ${guestPlayerCount}`);
            
            // Spezielle Regeln basierend auf Spielsystem
            if (playMode && playMode.toLowerCase().includes('braunschweiger')) {
                // Braunschweiger System: Beide müssen mindestens 4 Spieler haben
                const requiresMinPlayers = 4;
                const canBothPlay = homePlayerCount >= requiresMinPlayers && guestPlayerCount >= requiresMinPlayers;
                console.log(`📊 Braunschweiger System: Heim ${homePlayerCount} >= ${requiresMinPlayers} && Gast ${guestPlayerCount} >= ${requiresMinPlayers} = ${canBothPlay}`);
                return canBothPlay;
            } 
            else if (playMode && playMode.toLowerCase().includes('6er')) {
                // 6er System: Beide müssen mindestens 6 Spieler haben
                const requiresMinPlayers = 6;
                const canBothPlay = homePlayerCount >= requiresMinPlayers && guestPlayerCount >= requiresMinPlayers;
                console.log(`📊 6er System: Heim ${homePlayerCount} >= ${requiresMinPlayers} && Gast ${guestPlayerCount} >= ${requiresMinPlayers} = ${canBothPlay}`);
                return canBothPlay;
            }
            else {
                // 4er Systeme (einschließlich Standard): Beide müssen mindestens 4 Spieler haben
                const requiresMinPlayers = 4;
                const canBothPlay = homePlayerCount >= requiresMinPlayers && guestPlayerCount >= requiresMinPlayers;
                console.log(`📊 4er System: Heim ${homePlayerCount} >= ${requiresMinPlayers} && Gast ${guestPlayerCount} >= ${requiresMinPlayers} = ${canBothPlay}`);
                return canBothPlay;
            }
        },

        // Toggle Begrüßung abgeschlossen/nicht abgeschlossen
        toggleGreetingCompleted() {
            this.isGreetingCompleted = !this.isGreetingCompleted;
            
            if (this.isGreetingCompleted) {
                // Wechsle zu Ergebniserfassung nach dem Absschließen
                this.setActiveSection('result');
                console.log('🎯 Begrüßung abgeschlossen - wechsle zu Ergebniserfassung');
            } else {
                console.log('🎯 Begrüßung wieder geöffnet');
            }
        },

        // Formatiere Zeit für Anzeige
        formatTime(dateTime) {
            if (!dateTime) return '—';
            const date = new Date(dateTime);
            return date.toLocaleTimeString('de-DE', { 
                hour: '2-digit', 
                minute: '2-digit'
            });
        },

        // Setze aktuelle Zeit für Startzeit
        setCurrentStartTime() {
            const now = new Date();
            const timeString = now.toTimeString().substring(0, 8); // HH:MM:SS Format
            this.match.startDate = now;
            console.log(`📅 Startzeit gesetzt auf: ${timeString}`);
        },

        // Setze aktuelle Zeit für Endzeit mit intelligenter Navigation
        setEndTimeAndNavigate() {
            const now = new Date();
            const timeString = now.toTimeString().substring(0, 8); // HH:MM:SS Format
            this.match.endDate = now;
            console.log(`📅 Endzeit gesetzt auf: ${timeString}`);
            
            // Prüfe ob alle notwendigen Spiele abgeschlossen sind und navigiere
            this.checkAllMatchableCompletedAndNavigate();
        },

        // Setze aktuelle Zeit für Startzeit (Legacy für Kompatibilität)
        setCurrentEndTime() {
            this.setEndTimeAndNavigate();
        },

        // Auto-Fill für leere Matches
        autoFillEmptyMatches() {
            console.log('🔧 Starte Auto-Fill für leere Matches...');
            
            this.results.forEach((match, index) => {
                const hasHomePlayer = match.homeName && match.homeName.trim() !== '';
                const hasGuestPlayer = match.guestName && match.guestName.trim() !== '';
                
                console.log(`🔍 Match ${index + 1}: Heim="${match.homeName}", Gast="${match.guestName}"`);
                console.log(`   hat Heim-Spieler: ${hasHomePlayer}, hat Gast-Spieler: ${hasGuestPlayer}`);
                
                // Nur wenn genau ein Spieler vorhanden ist (der andere ist leer)
                if (hasHomePlayer && !hasGuestPlayer) {
                    console.log(`✅ Auto-Fill Match ${index + 1}: Heim ${match.homeName} gewinnt 3:0`);
                    this.autoFillMatch(index, 'home', 3, 0);
                } else if (!hasHomePlayer && hasGuestPlayer) {
                    console.log(`✅ Auto-Fill Match ${index + 1}: Gast ${match.guestName} gewinnt 3:0`);
                    this.autoFillMatch(index, 'guest', 0, 3);
                } else if (!hasHomePlayer && !hasGuestPlayer) {
                    console.log(`⏭️ Match ${index + 1}: Keine Spieler → überspringe`);
                } else {
                    console.log(`⏭️ Match ${index + 1}: Beide Spieler vorhanden → überspringe`);
                }
            });
        },

        autoFillMatch(matchIndex, winner, winnerGames, opponentGames) {
            if (matchIndex < 0 || matchIndex >= this.results.length) {
                console.error(`❌ Ungültiger Match-Index: ${matchIndex}`);
                return;
            }
            
            const match = this.results[matchIndex];
            
            // Setze 3 x 11:0 Sätze für den Gewinner
            for (let setIndex = 0; setIndex < 3; setIndex++) {
                if (winner === 'home') {
                    match.sets[setIndex] = '11:0';  // Heim gewinnt
                } else {
                    match.sets[setIndex] = '0:11';  // Gast gewinnt
                }
            }
            
            // Setze auch Satz 4 und 5 als leer
            if (match.sets[3] === undefined) match.sets[3] = '';
            if (match.sets[4] === undefined) match.sets[4] = '';
            
            // Berechne Match-Ergebnis neu
            this.calculateMatchResult(matchIndex);
            
            // Markiere Match als abgeschlossen
            this.completeMatch(matchIndex);
            
            console.log(`🎯 Match ${matchIndex + 1} gefüllt und abgeschlossen: ${JSON.stringify(match.sets)}`);
        },

        // Prüfe ob alle Spiele gespielt sind und navigiere evtl. zu Abschluss
        checkAndNavigateToCompletion() {
            console.log('🔍 Prüfe auf Abschluss-Bereitschaft...');
            
            if (!this.results || this.results.length === 0) {
                console.log('❌ Keine Ergebnisse vorhanden');
                return;
            }
            
            // Zähle abgeschlossene Matches
            const completedMatches = this.results.filter(match => match.completed);
            const totalMatches = this.results.length;
            const playThrough = this.getPlayThrough();
            
            console.log(`📊 Matches: ${completedMatches.length}/${totalMatches} abgeschlossen`);
            console.log(`🎮 Play Through: ${playThrough}`);
            
            // Prüfe ALLGAMES Modus
            if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
                // Im ALLGAMES Modus: alle Spiele müssen abgeschlossen sein
                if (completedMatches.length === totalMatches) {
                    console.log('✅ ALLGAMES: Alle Spiele abgeschlossen → springe zu Abschluss');
                    this.setActiveSection('completion');
                    return;
                } else {
                    console.log(`⚠️ ALLGAMES: Nur ${completedMatches.length}/${totalMatches} Spiele abgeschlossen`);
                    return;
                }
            } else {
                // Normal Mode: mindestens ein Spiel muss abgeschlossen sein
                if (completedMatches.length > 0) {
                    console.log(`✅ Normal Mode: ${completedMatches.length} Spiele abgeschlossen → springe zu Abschluss`);
                    this.setActiveSection('completion');
                    return;
                } else {
                    console.log('⚠️ Normal Mode: Keine Spiele abgeschlossen');
                    return;
                }
            }
        },

        // Prüfe ob alle abgeschliebaren Spiele tatsächlich abgeschlossen sind
        checkAllMatchableCompletedAndNavigate() {
            console.log('🔍 Prüfe alle abgeschliebbaren Matches...');
            
            if (!this.results || this.results.length === 0) {
                console.log('❌ Keine Ergebnisse vorhanden');
                return;
            }
            
                            // Vereinfachte Logik: Alle Matches sind matchable wenn sie abgeschlossen sind
            const completedMatches = this.results.filter(match => match.completed);
            const totalMatches = this.results.length;
            
            console.log(`📊 Abgeschlossene Matches: ${completedMatches.length}/${totalMatches}`);
            
            // Wenn alle Matches abgeschlossen sind, navigiere zu Abschluss
            if (completedMatches.length === totalMatches) {
                console.log('✅ Alle Matches sind abgeschlossen → springe zu Abschluss');
                this.setActiveSection('completion');
            } else {
                console.log(`⚠️ Nur ${completedMatches.length}/${totalMatches} Matches sind abgeschlossen`);
            }
        },

        // Intelligente Navigation nach Zertifizierung
        navigateAfterCertification() {
            console.log('🧭 Intelligente Navigation nach Zertifizierung...');

            if (this.teamNotAppeared !== null) {
                if (this.canOpenNextStages) {
                    this.setActiveSection('completion');
                    console.log('🎯 WO-Fall: angetretene Mannschaft signiert → Abschluss');
                } else {
                    this.setActiveSection('general');
                    console.log('🎯 WO-Fall: warte auf Signatur der angetretenen Mannschaft');
                }
                return;
            }
            
            // Prüfe ob beide Aufstellungen jetzt zertifiziert sind
            const bothCertified = this.isHomeLineupCertified && this.isGuestLineupCertified;
            console.log(`📋 Beide Aufstellungen zertifiziert: ${bothCertified}`);
            console.log(`📝 Begrüßung abgeschlossen: ${this.isGreetingCompleted}`);
            
            if (bothCertified) {
                // Beide Aufstellungen sind jetzt zertifiziert
                if (!this.isGreetingCompleted) {
                    // Begrüßung noch nicht abgeschlossen → zu Begrüßung
                    this.setActiveSection('greeting');
                    console.log('🎯 Beide Aufstellungen zertifiziert → Begrüßung');
                } else {
                    // Begrüßung bereits abgeschlossen → zu Ergebniserfassung
                    this.setActiveSection('result');
                    console.log('🎯 Beide Aufstellungen zertifiziert + Begrüßung abgeschlossen → Ergebniserfassung');
                }
            } else {
                // Nur eine Aufstellung zertifiziert → zu allgemeinem Tab
                this.setActiveSection('general');
                console.log('🎯 Nur eine Aufstellung zertifiziert → Allgemein');
            }
        },

        // Methoden für Abschluss-Seite
        getHomeDoublePairs() {
            if (!this.results || this.results.length === 0) return [];
            
            // Extrahiere Doppelpaare aus den tatsächlichen Match-Ergebnissen
            const pairs = [];
            
            this.results.forEach(match => {
                // Doppelpaare enthalten "/" im Namen
                if (match.homeName && match.homeName.includes(' / ')) {
                    if (!pairs.includes(match.homeName)) {
                        pairs.push(match.homeName);
                    }
                }
            });
            
            return pairs;
        },

        getHomeSinglePlayers() {
            if (!this.results || this.results.length === 0) return [];
            
            // Extrahiere Einzelspieler in der Reihenfolge ihres Auftretens
            const players = [];
            const seen = new Set();
            
            this.results.forEach(match => {
                if (match.homeName && match.homeName !== '' && !match.homeName.includes(' / ')) {
                    if (!seen.has(match.homeName)) {
                        seen.add(match.homeName);
                        players.push(match.homeName);
                    }
                }
            });
            
            return players;
        },

        getGuestDoublePairs() {
            if (!this.results || this.results.length === 0) return [];
            
            // Extrahiere Doppelpaare aus den tatsächlichen Match-Ergebnissen
            const pairs = [];
            
            this.results.forEach(match => {
                // Doppelpaare enthalten "/" im Namen
                if (match.guestName && match.guestName.includes(' / ')) {
                    if (!pairs.includes(match.guestName)) {
                        pairs.push(match.guestName);
                    }
                }
            });
            
            return pairs;
        },

        getGuestSinglePlayers() {
            if (!this.results || this.results.length === 0) return [];
            
            // Extrahiere Einzelspieler in der Reihenfolge ihres Auftretens
            const players = [];
            const seen = new Set();
            
            this.results.forEach(match => {
                if (match.guestName && match.guestName !== '' && !match.guestName.includes(' / ')) {
                    if (!seen.has(match.guestName)) {
                        seen.add(match.guestName);
                        players.push(match.guestName);
                    }
                }
            });
            
            return players;
        },

        getOverallMatchScore() {
            let homeWins = 0;
            let guestWins = 0;

            this.results.forEach(match => {
                if (match.completed) {
                    let matchHomeWins = 0;
                    let matchGuestWins = 0;
                    
                    match.sets.forEach(set => {
                        if (set && set.includes(':')) {
                            const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                            
                            if (home > guest) {
                                matchHomeWins++;
                            } else if (guest > home) {
                                matchGuestWins++;
                            }
                        }
                    });
                    
                    if (matchHomeWins > matchGuestWins) {
                        homeWins++;
                    } else if (matchGuestWins > matchHomeWins) {
                        guestWins++;
                    }
                }
            });
            
            return `${homeWins}:${guestWins}`;
        },

        getOverallSetScore() {
            let totalHomeSetsWon = 0;
            let totalGuestSetsWon = 0;

            this.results.forEach(match => {
                if (match.completed) {
                    match.sets.forEach(set => {
                        if (set && set.includes(':')) {
                            const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                            
                            if (home > guest) {
                                totalHomeSetsWon++;
                            } else if (guest > home) {
                                totalGuestSetsWon++;
                            }
                        }
                    });
                }
            });
            
            return `(${totalHomeSetsWon}:${totalGuestSetsWon})`;
        },

        initializeFinalPins() {
            // Nur lokale Klartext-PINs vorbefuellen, niemals nuscore-Hashes.
            this.finalHomePin = this.isLikelyPinHash(this.match.homePin) ? '' : (this.match.homePin || '');
            this.finalGuestPin = this.isLikelyPinHash(this.match.guestPin) ? '' : (this.match.guestPin || '');
        },

        // Text für den Absenden-Button basierend auf Zustand
        getSubmitButtonText() {
            if (this.isMatchCompleted) {
                return '✅ Spielbericht bereits abgesendet';
            } else if (!this.areAllMatchResultsValid()) {
                const playThrough = this.getPlayThrough();
                if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
                    if (this.canBothTeamsPlayAllGames()) {
                        const unfinishedMatches = this.results.filter(match => !match.completed);
                        return `❌ Spielbericht absenden (${unfinishedMatches.length} Spiel/e noch offen)`;
                    } else {
                        return '✅ Spielbericht absenden (Mannschaften unvollständig)';
                    }
                }
                return '❌ Spielbericht absenden (Ergebnisse fehlerhaft)';
            } else if (!this.areStartAndEndTimesValid()) {
                return '❌ Spielbericht absenden (Zeiten fehlerhaft)';
            } else {
                return '📝 Spielbericht absenden';
            }
        },

        // Prüfe ob Start- und Endzeiten korrekt festgelegt sind
        areStartAndEndTimesValid() {
            // Prüfe ob Startzeit festgelegt wurde
            if (!this.match.startDate) {
                console.log('❌ Startzeit ist nicht festgelegt');
                return false;
            }
            
            // Prüfe ob Endzeit festgelegt wurde
            if (!this.match.endDate) {
                console.log('❌ Endzeit ist nicht festgelegt');
                return false;
            }
            
            // Prüfe ob Endzeit nach Startzeit liegt
            const startTime = new Date(this.match.startDate).getTime();
            const endTime = new Date(this.match.endDate).getTime();
            
            if (endTime <= startTime) {
                console.log('⚠️ Endzeit liegt vor/vor Startzeit - korrigiere auf nächsten Tag...');
                // Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
                const nextDay = new Date(endTime);
                nextDay.setDate(nextDay.getDate() + 1);
                this.match.endDate = nextDay;
                console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
            }
            
            console.log('✅ Start- und Endzeiten sind korrekt');
            return true;
        },

        // Prüfe ob alle Matchergebnisse korrekt sind (für Spielbericht-Absendung)
        areAllMatchResultsValid() {
            if (!this.results || this.results.length === 0) {  
                return false;
            }
            
            // Spezielle Regel für ALLGAMES Spielmodus
            const playThrough = this.getPlayThrough();
            if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
                // Prüfe zuerst, ob beide Mannschaften genügend Spieler haben
                const canBothTeamsPlayFullGames = this.canBothTeamsPlayAllGames();
                
                if (!canBothTeamsPlayFullGames) {
                    console.log('✅ ALLGAMES Modus: Beide Mannschaften haben nicht genüged Spieler - Absenden trotzdem möglich');
                    // Validiere nur die vorhandenen/abgeschlossenen Matches, nicht alle müssen alle abgeschlossen sein
                } else {
                    // Alle Spiele müssen abgeschlossen sein
                    const unfinishedMatches = this.results.filter(match => !match.completed);
                    if (unfinishedMatches.length > 0) {
                        console.log(`❌ ALLGAMES Modus: ${unfinishedMatches.length} Spiel(e) noch nicht abgeschlossen`);
                        return false;
                    }
                    console.log('✅ ALLGAMES Modus: Alle Spiele sind abgeschlossen');
                }
            }
            
            for (let i = 0; i < this.results.length; i++) {
                const match = this.results[i];
                
                // Prüfe auf Lücken in der Sätze-Reihenfolge
                const gapIndices = this.hasGapInSets(match);
                if (gapIndices !== false && Array.isArray(gapIndices) && gapIndices.length > 0) {
                    console.log(`❌ Match ${i + 1}: Lücken gefunden bei Satz ${gapIndices.map(idx => idx + 1).join(', ')}`);
                    return false;
                }
                
                // Prüfe jeden Satz auf Validität (nur ausgefüllte Sätze)
                for (let j = 0; j < match.sets.length; j++) {
                    const set = match.sets[j];
                    if (set && set.trim().length > 0 && set.includes(':')) {
                        // Parse die Satzergebnisse
                        const [homeScoreStr, guestScoreStr] = set.split(':');
                        const homeScore = parseInt(homeScoreStr) || 0;
                        const guestScore = parseInt(guestScoreStr) || 0;
                        
                        const validationResult = this.validateSetScore(homeScore, guestScore, set);
                        if (!validationResult.isValid) {
                            console.log(`❌ Match ${i + 1}, Satz ${j + 1}: ${validationResult.error}`);
                            return false;
                        }
                    }
                }
                
                // Prüfe Match-Abschluss-Regeln wenn Match als abgeschlossen markiert ist
                if (match.completed) {
                    const completionValidation = this.validateMatchCompletion(i);
                    if (!completionValidation.isValid) {
                        console.log(`❌ Match ${i + 1}: ${completionValidation.error}`);
                        return false;
                    }
                }
            }
            
            console.log('✅ Alle Match-Ergebnisse sind korrekt');
            return true;
        },

        async submitMatchReport() {
            try {
                console.log('🚀 Starte Spielbericht-Absendung...');
                
                // Wenn eine Mannschaft nicht angetreten ist, keine Match-Ergebnisse oder Zeiten validieren
                const isTeamNotAppeared = this.teamNotAppeared !== null;
                
                if (!isTeamNotAppeared) {
                    // Validiere zuerst alle Match-Ergebnisse
                    if (!this.areAllMatchResultsValid()) {
                        const playThrough = this.getPlayThrough();
                        if (playThrough && playThrough.toUpperCase().includes('ALLGAMES') && this.canBothTeamsPlayAllGames()) {
                            const unfinishedMatches = this.results.filter(match => !match.completed);
                            alert(`❌ Der Spielbericht kann nicht abgesendet werden. Es müssen alle Spiele abgeschlossen sein.\n\n` +
                                  `📊 Aktueller Status:\n` +
                                  `• ${this.results.length} Spiele insgesamt\n` +
                                  `• ${this.results.length - unfinishedMatches.length} Spiele abgeschlossen\n` +
                                  `• ${unfinishedMatches.length} Spiele noch offen\n\n` +
                                  `Bitte schließen Sie alle offenen Spiele ab, bevor Sie den Spielbericht absenden.`);
                            return;
                        } else {
                            alert('❌ Der Spielbericht kann nicht abgesendet werden, da noch Fehler in den Match-Ergebnissen vorhanden sind. Bitte korrigieren Sie:\n\n' +
                                  '• Lücken in der Satze-Reihenfolge\n' +
                                  '• Ungültige Satzergebnisse\n' +
                                  '• Ungenerische Match-Abschlüsse\n\n' +
                                  'Überprüfen Sie die Ergebniserfassung.');
                            return;
                        }
                    }
                    
                    console.log('✅ Alle Match-Ergebnisse sind gültig - fahre fort...');
                    
                    // Validiere Start- und Endzeiten
                    if (!this.areStartAndEndTimesValid()) {
                        alert('❌ Der Spielbericht kann nicht abgesendet werden, da Start- oder Endzeit nicht festgelegt wurden.\n\n' +
                              'Bitte legen Sie sowohl Startzeit als auch Endzeit fest.');
                        return;
                    }
                    
                    console.log('✅ Alle Zeiten sind gültig - fahre fort...');
                } else {
                    console.log('⚠️ Mannschaft nicht angetreten - überspringe Match-Ergebnis- und Zeit-Validierung');
                }
                
                // WO-Fall: keine Aufstellungssignaturen erzwingen
                const isHomeNotAppeared = this.teamNotAppeared === 'home';
                const isGuestNotAppeared = this.teamNotAppeared === 'guest';

                if (this.teamNotAppeared === null && !isHomeNotAppeared && !this.isHomeLineupCertified) {
                    alert('❌ Der Spielbericht kann nicht abgesendet werden, da die Heimmannschaft ihre Aufstellung noch nicht signiert hat.\n\n' +
                          'Bitte signieren Sie die Aufstellung der Heimmannschaft, bevor Sie den Spielbericht absenden.');
                    return;
                }

                if (this.teamNotAppeared === null && !isGuestNotAppeared && !this.isGuestLineupCertified) {
                    alert('❌ Der Spielbericht kann nicht abgesendet werden, da die Gastmannschaft ihre Aufstellung noch nicht signiert hat.\n\n' +
                          'Bitte signieren Sie die Aufstellung der Gastmannschaft, bevor Sie den Spielbericht absenden.');
                    return;
                }
                
                console.log('✅ Alle Aufstellungen sind signiert - fahre fort...');
                
                // Validiere PINs (nur für angetretene Mannschaften)
                
                if (!isHomeNotAppeared && (!this.finalHomePin || this.finalHomePin.trim() === '')) {
                    alert('Bitte geben Sie die PIN des Heimvereins ein.');
                    return;
                }
                
                if (!isGuestNotAppeared && (!this.finalGuestPin || this.finalGuestPin.trim() === '')) {
                    alert('Bitte geben Sie die PIN des Gastvereins ein.');
                    return;
                }
                
                console.log('✅ PIN-Validierung erfolgreich');
                
                // Erstelle eine Kopie des ursprünglichen Match-Objekts
                console.log('📋 Erstelle Kopie des Match-Objekts...');
                const matchData = JSON.parse(JSON.stringify(this.match));
                console.log('✅ Match-Objekt kopiert');
                
                // Aktualisiere die Match-Daten mit unseren Eingaben
                console.log('🔄 Aktualisiere Match-Daten...');
                this.updateMatchData(matchData, { finalizeReport: true });
                console.log('✅ Match-Daten aktualisiert');
                // Für WebSocket-Broadcast: clubId und gameCode mitsenden
                const clubId = this.$store?.getters?.currentClub;
                if (clubId) matchData.clubId = String(clubId);
                if (this.match?.code) matchData.gameCode = this.match.code;
                
                // Sende die Daten an den Backend-Endpunkt
                console.log('📤 Sende Spielbericht an Backend...');
                const uuid = this.meetingData.nuLigaMeetingUuid;
                
                if (!uuid) {
                    throw new Error('nuLigaMeetingUuid nicht gefunden');
                }
                
                const validationPayload = JSON.parse(JSON.stringify(matchData));
                validationPayload.isCompleted = false;
                const validationResult = await this.validateReport(validationPayload);
                const validationErrors = Array.isArray(validationResult?.validationErrors) ? validationResult.validationErrors : [];
                if (validationResult?.resultState === 'VALIDATION_ERROR' || validationErrors.length > 0) {
                    const validationMessage = validationErrors.length > 0
                        ? validationErrors.join('\n')
                        : 'Validierung fehlgeschlagen';
                    throw new Error(validationMessage);
                }

                const submitPayload = validationResult?.object
                    ? JSON.parse(JSON.stringify(validationResult.object))
                    : matchData;
                submitPayload.isCompleted = true;
                if (!submitPayload.signature || typeof submitPayload.signature !== 'object') {
                    submitPayload.signature = {};
                }
                if (!isHomeNotAppeared && this.finalHomePin && this.finalHomePin.trim() !== '') {
                    submitPayload.homePin = this.finalHomePin.trim();
                }
                if (!isGuestNotAppeared && this.finalGuestPin && this.finalGuestPin.trim() !== '') {
                    submitPayload.guestPin = this.finalGuestPin.trim();
                }
                const response = await fetch(`${backendBaseUrl}/api/nuscore/submit/${uuid}`, {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(submitPayload)
                });
                
                const result = await response.json();
                
                if (!response.ok) {
                    const validationMessage = Array.isArray(result?.details?.validationErrors) && result.details.validationErrors.length > 0
                        ? result.details.validationErrors.join('\n')
                        : null;
                    throw new Error(validationMessage || result.error || `HTTP ${response.status}: ${response.statusText}`);
                }
                
                console.log('✅ Spielbericht erfolgreich abgesendet:', result);
                this.submitSucceeded = true;
                this.clearLocalDraft();
                alert('✅ Spielbericht erfolgreich abgesendet!');
                
                // Dialog schließen
                this.$emit('close');
                
            } catch (error) {
                console.error('❌ Fehler beim Absenden:', error);
                console.error('❌ Fehler-Stack:', error.stack);
                alert(this.getFriendlySubmitErrorMessage(error.message));
            }
        },

        async validateReport(matchDataOverride = null) {
            try {
                if (!this.meetingData || !this.meetingData.nuLigaMeetingUuid) {
                    console.warn('⚠️ Keine Meeting-UUID verfügbar für Validierung');
                    return null;
                }

                const matchData = matchDataOverride
                    ? JSON.parse(JSON.stringify(matchDataOverride))
                    : JSON.parse(JSON.stringify(this.match));

                if (!matchDataOverride) {
                    this.updateMatchData(matchData, { finalizeReport: false });
                }

                const uuid = this.meetingData.nuLigaMeetingUuid;
                
                console.log('🔄 Validiere Spielbericht...');
                
                const response = await fetch(`${backendBaseUrl}/api/nuscore/validate/${uuid}`, {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(matchData)
                });
                
                const result = await response.json();
                
                if (result?.object) {
                    const hydratedResult = JSON.parse(JSON.stringify(result.object));
                    this.applyCurrentLineupStateToPayload(hydratedResult);
                    this.meetingDetails = hydratedResult;
                    this.meetingData = {
                        ...(this.meetingData || {}),
                        ...JSON.parse(JSON.stringify(result.object))
                    };
                    this.applyLineupCertificationFromMeetingDetails();
                }

                if (response.ok) {
                    console.log('✅ Validierung erfolgreich:', result);
                    
                    // Zeige Validierungswarnungen falls vorhanden
                    if (result.validationWarnings && result.validationWarnings.length > 0) {
                        console.warn('⚠️ Validierungswarnungen:', result.validationWarnings);
                    }
                    
                    // Zeige Validierungsfehler falls vorhanden
                    if (result.validationErrors && result.validationErrors.length > 0) {
                        console.error('❌ Validierungsfehler:', result.validationErrors);
                    }
                } else {
                    console.warn('⚠️ Validierung mit Fehlern:', result);
                }

                return result;
                
            } catch (error) {
                console.error('❌ Fehler beim Validieren:', error);
                // Validierungsfehler sind nicht kritisch, daher kein Alert
                return null;
            }
        },

        updateMatchData(matchData, options = {}) {
            try {
                console.log('🔄 updateMatchData: Verwende kompletten Original-Meeting-Daten...');
                const { finalizeReport = false } = options;
                
                // Verwende ausschließlich die Meeting-Details vom /meetingdetails/:uuid Endpoint
                if (!this.meetingDetails) {
                    throw new Error('❌ meetingDetails nicht verfügbar - Meeting-Details müssen zuerst geladen werden');
                }
                const baseData = this.meetingDetails;
                
                // Das gesamte Original-Objekt als Basis verwenden (bestehende matchData überschreiben)
                Object.assign(matchData, baseData);
                
                // Unerwünschte Felder entfernen, die nicht vom /meetingdetails Endpoint kommen sollten:
                delete matchData.championsTieBreakSelected;
                delete matchData.code;
                delete matchData.date;
                delete matchData.guestMatchPoints;
                delete matchData.guestTeam;
                delete matchData.guestTeamId;
                delete matchData.homeMatchPoints;
                delete matchData.homeTeam;
                delete matchData.homeTeamId;
                delete matchData.id;
                delete matchData.leagueDetails;
                delete matchData.leagueId;
                delete matchData.locationId;
                delete matchData.time;
                
                // NUR unsere spezifischen Änderungen eintragen:
                
                const isHomeNotAppeared = this.teamNotAppeared === 'home';
                const isGuestNotAppeared = this.teamNotAppeared === 'guest';

                // Abschluss-PINs explizit auf die korrekten Team-Felder schreiben.
                // Im WO-Fall nur fuer die angetretene Mannschaft.
                if (!isHomeNotAppeared && this.finalHomePin && this.finalHomePin.trim() !== '') {
                    matchData.homePin = this.finalHomePin.trim();
                }
                if (!isGuestNotAppeared && this.finalGuestPin && this.finalGuestPin.trim() !== '') {
                    matchData.guestPin = this.finalGuestPin.trim();
                }

                const signature = this.ensureSignatureContainer(matchData);
                if (signature) {
                    signature.lineupSignatureHome = this.isHomeLineupCertified ? 'confirmed' : '';
                    signature.lineupSignatureGuest = this.isGuestLineupCertified ? 'confirmed' : '';
                }

                // Zwischenstände dürfen nie als bereits freigegeben an nuscore zurückgeschickt werden.
                matchData.isCompleted = finalizeReport;

                // Wenn eine Mannschaft nicht angetreten ist, nur wo-Flag und PIN der angetretenen Mannschaft setzen
                if (this.teamNotAppeared !== null) {
                    console.log('⚠️ Mannschaft nicht angetreten - nur wo-Flag und PIN der angetretenen Mannschaft werden gesetzt');
                    return;
                }
                
                // 1. Spieleranzahl aktualisieren (aus Aufstellung)
                matchData.playerCountHome = this.getSelectedPlayerCount('home');
                matchData.playerCountGuest = this.getSelectedPlayerCount('guest');
                
                // 1.1 Lokalen Aufstellungszustand in den Payload übernehmen
                this.applyCurrentLineupStateToPayload(matchData);

                // 1.2 Player-Positionen aktualisieren (Einzel + Doppel Positionen erfassen)
                this.updatePlayerPositions(matchData);
                
                // 2. Zeitangaben aktualisieren
                if (this.match.startDate) {
                    matchData.startDate = this.match.startDate.toISOString();
                }
                if (this.match.endDate) {
                    matchData.endDate = this.match.endDate.toISOString();
                }
                matchData.meetingsStartEndTimeEnabled = true;
                
                // 3. Protest-Informationen
                if (this.protestText && this.protestText.trim() !== '') {
                    matchData.protest = true;
                    matchData.remarks = this.protestText.trim();
                } else {
                    matchData.protest = false;
                    matchData.remarks = null;
                }
                
                // 5. PINs - Original-Hashes beibehalten (werden vom Backend beim Senden aktualisiert)
                // matchData.homePin und matchData.guestPin bleiben die ursprünglichen Hashes aus baseData
                
                // 6. Match-Status nur beim finalen Submit auf abgeschlossen setzen
                matchData.isCompleted = finalizeReport;
                
                // 7. Gesamtstatistik berechnen und eintragen
                const overallScore = this.getOverallMatchScore();
                
                // Gesamtpunkte berechnen und eintragen
                const [homeMatches, guestMatches] = overallScore.split(':').map(Number);
                matchData.homeMatches = homeMatches;
                matchData.guestMatches = guestMatches;
                
                // Match-Punkte (für Liga-Tabelle) - diese Felder werden vom Backend berechnet
                // homeMatchPoints und guestMatchPoints bleiben ursprünglich aus baseData
                
                // Gesamtsätze berechnen und eintragen
                const setScore = this.getOverallSetScore();
                const setScoreMatch = setScore.match(/\((\d+):(\d+)\)/);
                if (setScoreMatch) {
                    matchData.homeSets = parseInt(setScoreMatch[1]);
                    matchData.guestSets = parseInt(setScoreMatch[2]);
                }
                
                // 8. Gesamtpunkte (Games) berechnen und eintragen
                let totalHomeGames = 0;
                let totalGuestGames = 0;
                
                // Einzelne Matches aktualisieren - Originalarray verwenden und nur unsere Ergebnisse eintragen
                if (matchData.matches && Array.isArray(matchData.matches)) {
                        this.results.forEach((result, index) => {
                            if (matchData.matches[index]) {
                                const match = matchData.matches[index];
                                
                                // Reset aller Satzfelder auf 0 (Original hat meist schon Werte)
                                const setFields = ['set1A', 'set2A', 'set3A', 'set4A', 'set5A', 'set1B', 'set2B', 'set3B', 'set4B', 'set5B'];
                                setFields.forEach(field => {
                                    match[field] = 0;
                                });
                                
                                // Satzergebnisse aus unseren eingegebenen Daten eintragen
                                result.sets.forEach((set, setIndex) => {
                                    if (set && set.includes(':')) {
                                        const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                                        const setFieldA = `set${setIndex + 1}A`;
                                        const setFieldB = `set${setIndex + 1}B`;
                                        
                                        match[setFieldA] = home;
                                        match[setFieldB] = guest;
                                        
                                        // Gesamtpunkte (Games) sammeln
                                        totalHomeGames += home;
                                        totalGuestGames += guest;
                                    }
                                });
                                
                                // Match-Gewinner berechnen und eintragen
                                let homeWins = 0;
                                let guestWins = 0;
                                
                                if (result.completed) {
                                    result.sets.forEach(set => {
                                        if (set && set.includes(':')) {
                                            const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                                            if (home > guest) {
                                                homeWins++;
                                            } else if (guest > home) {
                                                guestWins++;
                                            }
                                        }
                                    });
                                }
                                
                                // Nur unsere geänderten Werte aktualisieren (Original bleibt erhalten)
                                match.matchesA = homeWins > guestWins ? 1 : 0;
                                match.matchesB = guestWins > homeWins ? 1 : 0;
                                match.setsA = homeWins;
                                match.setsB = guestWins;
                                match.isCompleted = result.completed;
                            }
                        });
                    }
                
                // 9. Gesamtpunkte (Games) eintragen
                matchData.homeGames = totalHomeGames;
                matchData.guestGames = totalGuestGames;
                
                // 9. Champions Tie-Break - wird NICHT hinzugefügt (Feld bleibt aus Original)
                
                console.log('✅ updateMatchData: Aktualisierung abgeschlossen');
                
            } catch (error) {
                console.error('❌ updateMatchData Fehler:', error);
                console.error('❌ updateMatchData Stack:', error.stack);
                throw error;
            }
        },

        // Aktualisiere die Player-Positionen um alle Positionen (Einzel + Doppel) zu erfassen
        updatePlayerPositions(matchData) {
            console.log('🔄 Aktualisiere Player-Positionen...');
            
            // Home Players Positionen aktualisieren
            if (matchData.teamLineupHomePlayers && Array.isArray(matchData.teamLineupHomePlayers)) {
                matchData.teamLineupHomePlayers.forEach(player => {
                    const positions = [];
                    
                    // Einzel-Position NUR hinzufügen wenn Spieler ausgewählt ist
                    if (player.isSelected) {
                        // Verwende positionSingle falls verfügbar, sonst rank für Einzel-Position
                        const singlePos = player.positionSingle || player.rank;
                        if (singlePos) {
                            player.positionSingle = singlePos;
                            positions.push(`E${singlePos}`);
                        }
                    } else {
                        player.positionSingle = null;
                    }
                    
                    // Doppel-Position NUR hinzufügen wenn Spieler Doppel-Position hat
                    if (player.positionDouble) {
                        positions.push(`D${player.positionDouble}`);
                    }
                    
                    player.positions = positions;
                    console.log(`✅ Home Player ${player.firstname} ${player.lastname}: [${positions.join(', ')}] (selected: ${player.isSelected})`);
                });
            }
            
            // Guest Players Positionen aktualisieren
            if (matchData.teamLineupGuestPlayers && Array.isArray(matchData.teamLineupGuestPlayers)) {
                matchData.teamLineupGuestPlayers.forEach(player => {
                    const positions = [];
                    
                    // Einzel-Position NUR hinzufügen wenn Spieler ausgewählt ist
                    if (player.isSelected) {
                        // Verwende positionSingle falls verfügbar, sonst rank für Einzel-Position
                        const singlePos = player.positionSingle || player.rank;
                        if (singlePos) {
                            player.positionSingle = singlePos;
                            positions.push(`E${singlePos}`);
                        }
                    } else {
                        player.positionSingle = null;
                    }
                    
                    // Doppel-Position NUR hinzufügen wenn Spieler Doppel-Position hat
                    if (player.positionDouble) {
                        positions.push(`D${player.positionDouble}`);
                    }
                    
                    player.positions = positions;
                    console.log(`✅ Guest Player ${player.firstname} ${player.lastname}: [${positions.join(', ')}] (selected: ${player.isSelected})`);
                });
            }
            
            console.log('✅ Player-Positionen aktualisiert');
        },

        applyCurrentLineupStateToPayload(target) {
            if (!target || typeof target !== 'object' || !this.meetingDetails) {
                return;
            }

            const copyTeamState = (teamKey) => {
                if (!Array.isArray(this.meetingDetails[teamKey]) || !Array.isArray(target[teamKey])) {
                    return;
                }

                const localByPersonId = new Map(
                    this.meetingDetails[teamKey]
                        .filter(player => player && player.nuLigaPersonId != null)
                        .map(player => [String(player.nuLigaPersonId), player])
                );

                target[teamKey] = target[teamKey].map((player) => {
                    if (!player || player.nuLigaPersonId == null) {
                        return player;
                    }

                    const localPlayer = localByPersonId.get(String(player.nuLigaPersonId));
                    if (!localPlayer) {
                        return player;
                    }

                    return {
                        ...player,
                        isSelected: Boolean(localPlayer.isSelected),
                        positionSingle: localPlayer.isSelected ? (localPlayer.positionSingle || null) : null,
                        positionDouble: localPlayer.isSelected ? (localPlayer.positionDouble || null) : null,
                        positions: Array.isArray(localPlayer.positions) ? [...localPlayer.positions] : []
                    };
                });
            };

            copyTeamState('teamLineupHomePlayers');
            copyTeamState('teamLineupGuestPlayers');

            const signature = this.ensureSignatureContainer(target);
            if (signature) {
                signature.lineupSignatureHome = this.isHomeLineupCertified ? 'confirmed' : '';
                signature.lineupSignatureGuest = this.isGuestLineupCertified ? 'confirmed' : '';
            }
        },


        // Zähle die ausgewählten Spieler für ein Team
        getSelectedPlayerCount(team) {
            try {
                if (team === 'home') {
                    const homePlayers = this.meetingDetails?.teamLineupHomePlayers || this.teamLineupHomePlayers || [];
                    return homePlayers.filter(p => p.isSelected === true && p.nuLigaPersonId > 0).length;
                } else if (team === 'guest') {
                    const guestPlayers = this.meetingDetails?.teamLineupGuestPlayers || this.teamLineupGuestPlayers || [];
                    return guestPlayers.filter(p => p.isSelected === true && p.nuLigaPersonId > 0).length;
                }
                return 0;
            } catch (error) {
                console.error('❌ getSelectedPlayerCount Fehler:', error);
                return 0;
            }
        },

        // Verwende die Matches aus dem Match-Objekt oder lasse vorhandene Ergebnisse bestehen
        initializeResults() {
            if (this.match.matches && Array.isArray(this.match.matches) && this.match.matches.length > 0) {
                // Verwende existierende Matches vom Server / aus nuscore-Synchronisation
                this.results = this.match.matches.map((match, index) => ({
                    homeName: match.homePlayer || (this.results[index] && this.results[index].homeName) || `Spieler Heim ${match.matchNumber || ''}`,
                    guestName: match.guestPlayer || (this.results[index] && this.results[index].guestName) || `Spieler Gast ${match.matchNumber || ''}`,
                    sets: match.sets || (this.results[index] && this.results[index].sets) || ['', '', '', '', ''],
                    completed: typeof match.completed === 'boolean' ? match.completed : ((this.results[index] && this.results[index].completed) || false),
                    result: match.result || (this.results[index] && this.results[index].result) || ''
                }));
            } else if (!this.results || this.results.length === 0) {
                // Fallback: Erstelle Default-Matches basierend auf Spielsystem, falls noch keine Ergebnisse existieren
                const playMode = (this.meetingDetails && this.meetingDetails.playMode) || 
                               (this.meetingData && (this.meetingData.playMode || this.meetingData.matchSystem || this.meetingData.system));
                const matchCount = this.getMatchCountForPlayMode(playMode);
                
                this.results = Array.from({ length: matchCount }, (_, index) => ({
                    homeName: `Spieler Heim ${index + 1}`,
                    guestName: `Spieler Gast ${index + 1}`,
                    sets: ['', '', '', '', ''], // 5 leere Sätze
                    completed: false,
                    result: ''
                }));
            }
        },

        formatMatchPlayerName(player) {
            if (!player || typeof player !== 'object') {
                return '';
            }
            return [player.firstname || player.firstName || '', player.lastname || player.lastName || '']
                .filter(Boolean)
                .join(' ')
                .trim();
        },

        formatMeetingMatchSide(match, side) {
            if (!match || typeof match !== 'object') {
                return '';
            }

            const firstPlayer = side === 'home' ? match.playerA1 : match.playerB1;
            const secondPlayer = side === 'home' ? match.playerA2 : match.playerB2;
            const firstName = this.formatMatchPlayerName(firstPlayer);
            const secondName = this.formatMatchPlayerName(secondPlayer);

            if (firstName && secondName) {
                return `${firstName} / ${secondName}`;
            }
            return firstName || secondName || '';
        },

        getMatchCountForPlayMode(playMode) {
            // Bestimme Anzahl der Spiele basierend auf Spielsystem
            switch (playMode) {
                case 'paarkreuz-system':
                    return 15; // 3 Doppel + 12 Einzel
                case 'bundessystem':
                    return 10; // 2 Doppel + 8 Einzel
                default:
                    return 10; // Standard
            }
        },

        // Synchronisiere die Ergebnisse zurück ins Match-Objekt
        syncResultsToMatch() {
            if (!this.match.matches) {
                this.match.matches = [];
            }
            
            // Synchronisiere jedes Ergebnis zurück
            this.results.forEach((result, index) => {
                if (!this.match.matches[index]) {
                    this.match.matches[index] = {};
                }
                
                // Synchronisiere die relevanten Daten
                this.match.matches[index].homePlayer = result.homeName;
                this.match.matches[index].guestPlayer = result.guestName;
                this.match.matches[index].sets = result.sets;
                this.match.matches[index].completed = result.completed;
                this.match.matches[index].result = result.result;
            });
        },

        async loadData() {
            this.loading = true;
            this.error = null;

            try {
                // Zuerst Cookies initialisieren
                await fetch(`${backendBaseUrl}/api/nuscore/init-cookies/${this.match.code}`, {
                    method: 'POST'
                });

                // Dann Meeting-Daten laden
                const response = await fetch(`${backendBaseUrl}/api/nuscore/meetinginfo/${this.match.code}`);

                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }

                this.meetingData = await response.json();
                console.log('[nuscore] /meetinginfo response:', this.meetingData);

                // Initialisiere "Nicht angetreten"-Wert aus meetingData
                if (this.meetingData.teamNotAppeared !== undefined) {
                    this.teamNotAppeared = this.meetingData.teamNotAppeared;
                } else if (this.meetingData.homeTeamNotAppeared !== undefined || this.meetingData.guestTeamNotAppeared !== undefined) {
                    // Migration: Alte boolean-Werte in neuen Wert umwandeln
                    if (this.meetingData.homeTeamNotAppeared) {
                        this.teamNotAppeared = 'home';
                    } else if (this.meetingData.guestTeamNotAppeared) {
                        this.teamNotAppeared = 'guest';
                    } else {
                        this.teamNotAppeared = null;
                    }
                } else if (this.meetingData.wo) {
                    // Wenn wo bereits gesetzt ist, leite daraus teamNotAppeared ab
                    this.teamNotAppeared = this.meetingData.wo === 'A' ? 'home' : (this.meetingData.wo === 'B' ? 'guest' : null);
                }

                // Lade detaillierte Meeting-Daten falls UUID verfügbar
                if (this.meetingData.nuLigaMeetingUuid) {
                    try {
                        const detailsResponse = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${this.meetingData.nuLigaMeetingUuid}`);
                        if (detailsResponse.ok) {
                            this.meetingDetails = await detailsResponse.json();
                            this.lastMeetingDetailsSignature = this.buildMeetingDetailsSignature(this.meetingDetails);
                            console.log('[nuscore] /meetingdetails response:', this.meetingDetails);
                            this.logBraunschweigerDebugSnapshot('Server /meetingdetails');
                        }
                    } catch (detailsError) {
                        console.warn('⚠️ Detaillierte Meeting-Daten konnten nicht geladen werden:', detailsError);
                    }
                }

                this.initialCompletionState = Boolean(
                    ((typeof this.meetingDetails?.isCompleted === 'boolean' && this.meetingDetails.isCompleted) && this.hasReleaseSignatureForCompletion(this.meetingDetails)) ||
                    ((typeof this.meetingData?.isCompleted === 'boolean' && this.meetingData.isCompleted) && this.hasReleaseSignatureForCompletion(this.meetingData))
                );

                // PINs automatisch laden
                this.loadPinsAutomatically();

                // Aufstellungs-Bestätigung aus nuscore übernehmen (wenn bereits signiert)
                this.applyLineupCertificationFromMeetingDetails();

                // Vereins-Einstellungen für Begrüßung laden
                await this.loadClubSettings();

                // Setze Standardwert für Spielbeginn aus vorhandenen Daten, falls noch nicht gesetzt
                if (!this.match.startDate) {
                    const startDate =
                        this.meetingDetails?.startDate ||
                        this.meetingData?.startDate ||
                        this.meetingDetails?.scheduleDate ||
                        this.meetingData?.scheduleDate;
                    if (startDate) {
                        this.match.startDate = new Date(startDate);
                        console.log('✅ Spielbeginn auf Standardwert gesetzt:', this.match.startDate);
                    }
                }

                // Spielende aus Meeting-Daten übernehmen, falls vorhanden
                if (!this.match.endDate) {
                    const endDate = this.meetingDetails?.endDate || this.meetingData?.endDate;
                    if (endDate) {
                        this.match.endDate = new Date(endDate);
                        console.log('✅ Spielende auf vorhandenen Wert gesetzt:', this.match.endDate);
                    }
                }

                // Ergebnisse initial auf Basis der Matrix vorbereiten (Namen/Zuweisungen)
                this.prepareResults();

                // Bereits vorhandene Satzergebnisse aus nuscore übernehmen (falls vorhanden)
                this.populateResultsFromMeetingDetails();

                // Wenn teamNotAppeared gesetzt ist und die Daten noch nicht angepasst wurden, wende die Anpassung an
                if (this.teamNotAppeared !== null && !this.meetingData.wo) {
                    this.applyTeamNotAppeared();
                }

            } catch (error) {
                console.error('❌ Fehler beim Laden der Meeting-Daten:', error);
                this.error = error.message;
            } finally {
                this.loading = false;
            }
        },
        prepareResults() {
            const matrix = this.currentPlayModeMatrix;
            this.results = (matrix || []).map((label) => ({
                label,
                homeName: this.resolveSide(label, 'home'),
                guestName: this.resolveSide(label, 'guest'),
                sets: ['', '', '', '', ''],
                completed: false,
                result: '1:0'
            }));
        },
        populateResultsFromMeetingDetails() {
            if (!this.meetingDetails || !Array.isArray(this.meetingDetails.matches)) {
                return;
            }

            const sourceMatches = this.meetingDetails.matches;
            const count = Math.min((this.results && this.results.length) || 0, sourceMatches.length);

            for (let i = 0; i < count; i++) {
                const src = sourceMatches[i] || {};
                const dst = this.results[i];

                const resolvedHomeName = this.formatMeetingMatchSide(src, 'home');
                const resolvedGuestName = this.formatMeetingMatchSide(src, 'guest');
                const fallbackHomeName = typeof src.homePlayer === 'string' ? src.homePlayer.trim() : '';
                const fallbackGuestName = typeof src.guestPlayer === 'string' ? src.guestPlayer.trim() : '';

                if (typeof src.name === 'string' && src.name.trim() !== '') {
                    dst.label = src.name.trim();
                }
                if (resolvedHomeName || fallbackHomeName) {
                    dst.homeName = resolvedHomeName || fallbackHomeName;
                }
                if (resolvedGuestName || fallbackGuestName) {
                    dst.guestName = resolvedGuestName || fallbackGuestName;
                }

                if (!dst.sets || !Array.isArray(dst.sets)) {
                    this.$set(dst, 'sets', ['', '', '', '', '']);
                }

                let anySet = false;

                for (let s = 0; s < dst.sets.length; s++) {
                    const homeKey = `set${s + 1}A`;
                    const guestKey = `set${s + 1}B`;
                    const rawHome = src[homeKey];
                    const rawGuest = src[guestKey];

                    const home = typeof rawHome === 'number' ? rawHome : parseInt(rawHome || 0);
                    const guest = typeof rawGuest === 'number' ? rawGuest : parseInt(rawGuest || 0);

                    if ((home || 0) > 0 || (guest || 0) > 0) {
                        dst.sets[s] = `${home}:${guest}`;
                        anySet = true;
                    } else if (!dst.sets[s]) {
                        dst.sets[s] = '';
                    }
                }

                // Versuche, den Abschlussstatus aus nuscore zu übernehmen
                if (typeof src.matchesA !== 'undefined' || typeof src.matchesB !== 'undefined') {
                    dst.completed = src.matchesA === 1 || src.matchesB === 1;
                } else if (anySet) {
                    const homeWins = this.getPlayerSetWins(dst, 'home');
                    const guestWins = this.getPlayerSetWins(dst, 'guest');
                    dst.completed = homeWins >= 3 || guestWins >= 3;
                }

                this.calculateMatchResult(i);
            }

            // Synchronisiere in das Match-Objekt, damit initializeResults() darauf zurückgreifen kann
            this.syncResultsToMatch();
        },
        applyTeamNotAppeared() {
            if (!this.meetingData || this.teamNotAppeared === null) {
                return;
            }

            const woValue = this.teamNotAppeared === 'home' ? 'A' : 'B'; // A = Home, B = Guest

            // Setze nur das wo-Flag im meetingData - nichts anderes ändern
            this.meetingData.wo = woValue;

            console.log('✅ Team "Nicht angetreten" angewendet:', this.teamNotAppeared, 'wo:', woValue);
        },

        /**
         * Setzt die Aufstellungs-Bestätigung (certified) aus den Meeting-Details.
         * Wichtig: NICHT aus homePin/guestPin ableiten. Diese Hashes koennen bereits
         * vor einer bestaetigten Aufstellung vorhanden sein und sind nur fuer die
         * PIN-Validierung gedacht.
         */
        applyLineupCertificationFromMeetingDetails() {
            const state = this.getExplicitLineupCertificationState();
            if (state.home !== null) {
                this.isHomeLineupCertified = state.home;
            }
            if (state.guest !== null) {
                this.isGuestLineupCertified = state.guest;
            }
        },

        ensureSignatureContainer(target) {
            if (!target || typeof target !== 'object') {
                return null;
            }
            if (!target.signature || typeof target.signature !== 'object') {
                target.signature = {};
            }
            return target.signature;
        },

        setLineupCertificationState(team, certified) {
            const teamSuffix = team === 'home' ? 'Home' : 'Guest';
            const signatureField = `lineupSignature${teamSuffix}`;
            const signatureValue = certified ? 'confirmed' : '';

            if (team === 'home') {
                this.isHomeLineupCertified = certified;
            } else {
                this.isGuestLineupCertified = certified;
            }

            [this.meetingDetails, this.meetingData].forEach((source) => {
                const signature = this.ensureSignatureContainer(source);
                if (!signature) {
                    return;
                }
                signature[signatureField] = signatureValue;
            });
        },

        normalizeCertificationValue(value) {
            if (typeof value === 'boolean') return value;
            if (typeof value === 'number') {
                if (value === 1) return true;
                if (value === 0) return false;
                return null;
            }
            if (typeof value !== 'string') return null;

            const normalized = value.trim().toLowerCase();
            const trueValues = new Set(['true', '1', 'yes', 'done', 'signed', 'confirmed', 'certified', 'complete', 'completed', 'reviewed', 'locked', 'readonly', 'read-only']);
            const falseValues = new Set(['false', '0', 'no', 'open', 'editable', 'pending', 'draft', 'unlocked']);

            if (trueValues.has(normalized)) return true;
            if (falseValues.has(normalized)) return false;
            return null;
        },

        readValueByPath(source, path) {
            return path.split('.').reduce((current, segment) => {
                if (current == null || typeof current !== 'object') {
                    return undefined;
                }
                return current[segment];
            }, source);
        },

        extractTeamCertificationFromSource(source, team) {
            if (!source || typeof source !== 'object') return null;

            const lineupSignaturePath = team === 'home'
                ? 'signature.lineupSignatureHome'
                : 'signature.lineupSignatureGuest';
            const lineupSignatureValue = this.readValueByPath(source, lineupSignaturePath);
            if (lineupSignatureValue !== undefined) {
                return typeof lineupSignatureValue === 'string'
                    ? lineupSignatureValue.trim() !== ''
                    : Boolean(lineupSignatureValue);
            }

            if (Object.prototype.hasOwnProperty.call(source, 'signature') && source.signature === null) {
                return false;
            }

            const teamMarkers = team === 'home'
                ? ['home', 'cluba', 'teama', 'lineuphome', 'homelineup']
                : ['guest', 'clubb', 'teamb', 'lineupguest', 'guestlineup'];
            const statusMarkers = ['certified', 'signed', 'confirmed', 'reviewed', 'clearance', 'locked', 'readonly', 'signature'];

            const walk = (value, path = []) => {
                if (!value || typeof value !== 'object') return null;

                for (const [rawKey, child] of Object.entries(value)) {
                    const key = String(rawKey);
                    const nextPath = [...path, key];
                    const joinedPath = nextPath.join('.').toLowerCase();

                    if (!joinedPath.includes('pin') &&
                        teamMarkers.some(marker => joinedPath.includes(marker)) &&
                        statusMarkers.some(marker => joinedPath.includes(marker))) {
                        if (joinedPath.includes('lineupsignature') && typeof child === 'string') {
                            return child.trim() !== '';
                        }
                        const normalized = this.normalizeCertificationValue(child);
                        if (normalized !== null) {
                            return normalized;
                        }
                    }

                    if (child && typeof child === 'object') {
                        const nested = walk(child, nextPath);
                        if (nested !== null) {
                            return nested;
                        }
                    }
                }

                return null;
            };

            return walk(source);
        },

        getExplicitLineupCertificationState() {
            const state = { home: null, guest: null };

            for (const source of [this.meetingDetails, this.meetingData]) {
                if (state.home === null) {
                    state.home = this.extractTeamCertificationFromSource(source, 'home');
                }
                if (state.guest === null) {
                    state.guest = this.extractTeamCertificationFromSource(source, 'guest');
                }
            }

            return state;
        },

        getDraftStorageKey() {
            const code = this.match?.code ? String(this.match.code) : '';
            const uuid = this.meetingData?.nuLigaMeetingUuid ? String(this.meetingData.nuLigaMeetingUuid) : '';
            if (!code && !uuid) return null;
            return `matchReportDraft:${code || uuid}:${uuid || 'nouuid'}`;
        },
        buildLocalDraftPayload() {
            return {
                savedAt: Date.now(),
                activeSection: this.activeSection,
                teamNotAppeared: this.teamNotAppeared,
                homePin: this.homePin,
                guestPin: this.guestPin,
                finalHomePin: this.finalHomePin,
                finalGuestPin: this.finalGuestPin,
                protestText: this.protestText,
                matchStartDate: this.match?.startDate || null,
                matchEndDate: this.match?.endDate || null,
                isHomeLineupCertified: this.isHomeLineupCertified,
                isGuestLineupCertified: this.isGuestLineupCertified,
                results: JSON.parse(JSON.stringify(this.results || [])),
                meetingDetails: this.meetingDetails ? {
                    signature: this.meetingDetails.signature ? { ...this.meetingDetails.signature } : null,
                    teamLineupHomePlayers: Array.isArray(this.meetingDetails.teamLineupHomePlayers)
                        ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupHomePlayers))
                        : [],
                    teamLineupGuestPlayers: Array.isArray(this.meetingDetails.teamLineupGuestPlayers)
                        ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupGuestPlayers))
                        : []
                } : null
            };
        },
        persistLocalDraft() {
            const key = this.getDraftStorageKey();
            if (!key) return;
            try {
                this.draftLastSavedAt = Date.now();
                window.localStorage.setItem(key, JSON.stringify(this.buildLocalDraftPayload()));
            } catch (error) {
                console.warn('⚠️ Draft konnte nicht lokal gespeichert werden:', error);
            }
        },
        persistLocalDraftDebounced() {
            if (this.draftPersistTimer) {
                clearTimeout(this.draftPersistTimer);
            }
            this.draftPersistTimer = setTimeout(() => {
                this.draftPersistTimer = null;
                this.persistLocalDraft();
            }, 250);
        },
        restoreLocalDraft() {
            const key = this.getDraftStorageKey();
            if (!key) return;
            try {
                const raw = window.localStorage.getItem(key);
                if (!raw) return;
                const draft = JSON.parse(raw);
                if (!draft || typeof draft !== 'object') return;
                this.draftLastSavedAt = draft.savedAt || Date.now();

                if (draft.matchStartDate) this.match.startDate = draft.matchStartDate;
                if (draft.matchEndDate) this.match.endDate = draft.matchEndDate;
                if (draft.activeSection) this.activeSection = draft.activeSection;
                if (typeof draft.teamNotAppeared !== 'undefined') this.teamNotAppeared = draft.teamNotAppeared;
                if (typeof draft.homePin === 'string') this.homePin = draft.homePin;
                if (typeof draft.guestPin === 'string') this.guestPin = draft.guestPin;
                if (typeof draft.finalHomePin === 'string') this.finalHomePin = draft.finalHomePin;
                if (typeof draft.finalGuestPin === 'string') this.finalGuestPin = draft.finalGuestPin;
                if (typeof draft.protestText === 'string') this.protestText = draft.protestText;
                if (Array.isArray(draft.results) && draft.results.length > 0) {
                    this.results = JSON.parse(JSON.stringify(draft.results));
                    this.syncResultsToMatch();
                }
                if (draft.meetingDetails && this.meetingDetails) {
                    if (Array.isArray(draft.meetingDetails.teamLineupHomePlayers)) {
                        this.meetingDetails.teamLineupHomePlayers = JSON.parse(JSON.stringify(draft.meetingDetails.teamLineupHomePlayers));
                    }
                    if (Array.isArray(draft.meetingDetails.teamLineupGuestPlayers)) {
                        this.meetingDetails.teamLineupGuestPlayers = JSON.parse(JSON.stringify(draft.meetingDetails.teamLineupGuestPlayers));
                    }
                    if (draft.meetingDetails.signature && typeof draft.meetingDetails.signature === 'object') {
                        this.meetingDetails.signature = { ...(this.meetingDetails.signature || {}), ...draft.meetingDetails.signature };
                    }
                }
                this.isHomeLineupCertified = Boolean(draft.isHomeLineupCertified);
                this.isGuestLineupCertified = Boolean(draft.isGuestLineupCertified);
            } catch (error) {
                console.warn('⚠️ Draft konnte nicht wiederhergestellt werden:', error);
            }
        },
        clearLocalDraft() {
            const key = this.getDraftStorageKey();
            if (!key) return;
            try {
                window.localStorage.removeItem(key);
            } catch (error) {
                // ignore
            }
        },
        syncDraftToServerDebounced(delayMs = 600) {
            if (this.draftSyncTimer) {
                clearTimeout(this.draftSyncTimer);
            }
            this.draftSyncTimer = setTimeout(async () => {
                this.draftSyncTimer = null;
                await this.syncDraftToServer();
            }, delayMs);
        },
        async syncDraftToServer() {
            if (this.isDraftSyncing || !this.meetingData?.nuLigaMeetingUuid) {
                return;
            }
            this.isDraftSyncing = true;
            this.lastDraftSyncError = '';
            try {
                const matchData = JSON.parse(JSON.stringify(this.match));
                this.updateMatchData(matchData, { finalizeReport: false });
                await this.validateReport(matchData);
                this.draftLastSyncedAt = Date.now();
            } catch (error) {
                this.lastDraftSyncError = error?.message || 'sync_failed';
                console.warn('⚠️ Draft-Sync zu nuscore fehlgeschlagen:', error);
            } finally {
                this.isDraftSyncing = false;
            }
        },
        /** Entwurf für Broadcast: meetingDetails-Form mit aktuellen Satzergebnissen aus results. */
        getDraftMatchData() {
            if (!this.meetingDetails || !Array.isArray(this.meetingDetails.matches)) return null;
            const matches = this.meetingDetails.matches.map((m, i) => {
                const r = this.results[i];
                const out = { ...m };
                if (r && Array.isArray(r.sets)) {
                    for (let s = 0; s < 5; s++) {
                        const setStr = r.sets[s];
                        if (setStr && String(setStr).includes(':')) {
                            const parts = String(setStr).split(':').map(x => parseInt(x, 10) || 0);
                            out[`set${s + 1}A`] = parts[0];
                            out[`set${s + 1}B`] = parts[1];
                        }
                    }
                }
                return out;
            });
            return {
                matches,
                signature: this.meetingDetails.signature ? { ...this.meetingDetails.signature } : undefined,
                teamLineupHomePlayers: Array.isArray(this.meetingDetails.teamLineupHomePlayers)
                    ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupHomePlayers))
                    : undefined,
                teamLineupGuestPlayers: Array.isArray(this.meetingDetails.teamLineupGuestPlayers)
                    ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupGuestPlayers))
                    : undefined,
                homePin: this.meetingDetails.homePin,
                guestPin: this.meetingDetails.guestPin,
                startDate: this.meetingData?.startDate ?? this.match?.startDate,
                endDate: this.meetingData?.endDate ?? this.match?.endDate
            };
        },
        async broadcastDraft() {
            const clubId = this.$store?.getters?.currentClub;
            const gameCode = this.match?.code;
            const matchData = this.getDraftMatchData();
            if (!clubId || !gameCode || !matchData) return;
            try {
                await apiClient.post('/nuscore/broadcast-draft', { clubId: String(clubId), gameCode, matchData });
            } catch (e) {
                // still, no hard error for draft broadcast
            }
        },
        broadcastDraftDebounced() {
            if (this.broadcastDraftTimer) clearTimeout(this.broadcastDraftTimer);
            this.broadcastDraftTimer = setTimeout(() => {
                this.broadcastDraftTimer = null;
                this.broadcastDraft();
            }, 500);
        },

        /**
         * Übernimmt per WebSocket empfangene Match-Daten (von anderem Gerät) in den Dialog.
         * Aktualisiert meetingDetails und meetingData, dann Ergebnisse und Aufstellungs-Bestätigung.
         */
        applyReceivedMatchData(matchData) {
            if (!matchData || !this.meetingDetails) return;
            if (Array.isArray(matchData.matches)) {
                this.meetingDetails.matches = matchData.matches;
            }
            if (matchData.signature && typeof matchData.signature === 'object') {
                this.meetingDetails.signature = { ...(this.meetingDetails.signature || {}), ...matchData.signature };
            }
            if (Array.isArray(matchData.teamLineupHomePlayers)) {
                this.meetingDetails.teamLineupHomePlayers = matchData.teamLineupHomePlayers;
            }
            if (Array.isArray(matchData.teamLineupGuestPlayers)) {
                this.meetingDetails.teamLineupGuestPlayers = matchData.teamLineupGuestPlayers;
            }
            if (matchData.homePin != null) this.meetingDetails.homePin = matchData.homePin;
            if (matchData.guestPin != null) this.meetingDetails.guestPin = matchData.guestPin;
            if (matchData.startDate != null && this.meetingData) this.meetingData.startDate = matchData.startDate;
            if (matchData.endDate != null && this.meetingData) this.meetingData.endDate = matchData.endDate;
            this.populateResultsFromMeetingDetails();
            this.applyLineupCertificationFromMeetingDetails();
        },
        resolveSide(label, side) {
            // label z.B. "A1 – B2" oder "DA1 – DB1"
            try {
                const parts = label.split('–').map(s => s.trim());
                const token = side === 'home' ? parts[0] : parts[1];
                if (!token) return '';
                
                if (token.startsWith('DA') || token.startsWith('DB')) {
                    // Doppel-Name aus den gesetzten Doppeln ableiten
                    const pos = parseInt(token.replace(/[^0-9]/g, '')); // 1 oder 2
                    const key = side === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
                    const list = (this.meetingDetails && this.meetingDetails[key]) ? this.meetingDetails[key] : [];
                    const pair = list.filter(p => p.positionDouble === pos && p.nuLigaPersonId > 0);
                    const n = (p) => [p.firstname || p.firstName || '', p.lastname || p.lastName || ''].filter(Boolean).join(' ').trim();
                    
                    // Wenn ein Doppel-Paar gefunden wurde, verwende es
                    if (pair.length >= 2) {
                        const result = `${n(pair[0])} / ${n(pair[1])}`;
                        return result;
                    }
                    if (pair.length === 1) {
                        const result = `${n(pair[0])}`;
                        return result;
                    }
                    
                    // Falls kein Doppel gefunden, verwende die entsprechenden Spieler basierend auf der Position
                    if (pair.length === 0) {
                        const selectedPlayers = list.filter(p => p.isSelected && p.nuLigaPersonId > 0);
                        
                        
                        // Versuche verschiedene Sortierungen
                        // 1. Zuerst nach positionDouble (falls vorhanden)
                        // 2. Dann nach rank
                        // 3. Dann nach der Reihenfolge in der Liste
                        const sortedPlayers = selectedPlayers.sort((a, b) => {
                            // Spieler mit positionDouble zuerst
                            if (a.positionDouble && !b.positionDouble) return -1;
                            if (!a.positionDouble && b.positionDouble) return 1;
                            if (a.positionDouble && b.positionDouble) {
                                return a.positionDouble - b.positionDouble;
                            }
                            
                            // Dann nach rank
                            if (a.rank !== b.rank) {
                                return a.rank - b.rank;
                            }
                            
                            // Dann nach positions
                            const aPos = (a.positions && a.positions.length > 0) ? a.positions[0] : 'Z';
                            const bPos = (b.positions && b.positions.length > 0) ? b.positions[0] : 'Z';
                            return aPos.localeCompare(bPos);
                        });
                        
                        
                        // Für DA1/DB1: Spieler 0+1, für DA2/DB2: Spieler 2+3, etc.
                        const startIndex = (pos - 1) * 2;
                        if (sortedPlayers.length > startIndex + 1) {
                            const result = `${n(sortedPlayers[startIndex])} / ${n(sortedPlayers[startIndex + 1])}`;
                            return result;
                        } else if (sortedPlayers.length > startIndex) {
                            const result = n(sortedPlayers[startIndex]);
                            return result;
                        } else if (sortedPlayers.length >= 2) {
                            // Fallback: zirkulieren
                            const index1 = startIndex % sortedPlayers.length;
                            const index2 = (startIndex + 1) % sortedPlayers.length;
                            const result = `${n(sortedPlayers[index1])} / ${n(sortedPlayers[index2])}`;
                            return result;
                        } else if (sortedPlayers.length === 1) {
                            const result = n(sortedPlayers[0]);
                            return result;
                        }
                    }
                    
                    return token;
                } else {
                    // Einzelposition A1..A6 / B1..B6
                    const isHome = token.startsWith('A');
                    const rank = parseInt(token.replace(/[^0-9]/g, ''));
                    const team = (isHome ? 'home' : 'guest');
                    const key = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
                    const list = (this.meetingDetails && this.meetingDetails[key]) ? this.meetingDetails[key] : [];
                    
                    // Prüfe zuerst, ob überhaupt genügend Spieler für diese Position vorhanden sind
                    const selectedPlayers = list.filter(p => p.isSelected && p.nuLigaPersonId > 0);
                    
                    // Für Braunschweiger System: 2er-Mannschaften werden als 3er-Mannschaften gewertet
                    let effectivePlayerCount = selectedPlayers.length;
                    const playMode = this.getPlayMode();
                    if (playMode && playMode.toLowerCase().includes('braunschweiger') && selectedPlayers.length === 2) {
                        effectivePlayerCount = 3;
                    }
                    
                    if (effectivePlayerCount < rank) {
                        // Nicht genügend Spieler für diese Position → Position bleibt leer
                        return '';
                    }
                    
                    // Suche nach Spieler mit entsprechender Position
                    // Zuerst nach A1, A2, etc. in positions Array (für Standard-Aufstellungen)
                    let player = list.find(p => p.isSelected && (p.positions || []).includes(`${isHome ? 'A' : 'B'}${rank}`));
                    
                    // Falls immer noch nicht gefunden, suche nach Spielern mit E1, E2, etc. in positions
                    if (!player) {
                        player = list.find(p => p.isSelected && (p.positions || []).includes(`E${rank}`));
                    }
                    
                    // Falls immer noch nicht gefunden, nach Reihenfolge in der Liste der ausgewählten Spieler
                    if (!player) {
                        // Da wir bereits oben geprüft haben, dass genügend Spieler vorhanden sind,
                        // können wir sicher den entsprechenden Spieler verwenden
                        const sortedPlayers = selectedPlayers.sort((a, b) => {
                            const aPos = (a.positions && a.positions.length > 0) ? a.positions[0] : 'Z';
                            const bPos = (b.positions && b.positions.length > 0) ? b.positions[0] : 'Z';
                            return aPos.localeCompare(bPos);
                        });
                        
                        player = sortedPlayers[rank - 1];
                    }
                    
                    if (!player) return '';
                    const result = [player.firstname || player.firstName || '', player.lastname || player.lastName || ''].filter(Boolean).join(' ').trim();
                    return result;
                }
            } catch (e) {
                console.warn('Fehler beim Auflösen der Spielerseite:', e, 'label:', label, 'side:', side);
                return '';
            }
        },
        completeMatch(idx) {
            const m = this.results[idx];
            
            // Validiere ob Match korrekt abgeschlossen werden kann
            const validationResult = this.validateMatchCompletion(idx);
            
            if (!validationResult.isValid) {
                // Zeige Fehlermeldung an
                this.errors[idx] = validationResult.error;
                return;
            }
            
            // Match erfolgreich abschließen
            m.completed = true;
            this.clearMatchError(idx);
            
            // Synchronisiere zurück ins Match-Objekt
            this.syncResultsToMatch();
            this.broadcastDraftDebounced();
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(800);
        },

        appendToSet(matchIndex, setIndex, char) {
            if (!this.results || !this.results[matchIndex]) return;
            const sets = this.results[matchIndex].sets || [];
            const current = sets[setIndex] || '';
            // Einfache Längenbegrenzung, damit die Eingabe übersichtlich bleibt
            if (current.length >= 5) {
                return;
            }
            this.results[matchIndex].sets[setIndex] = current + char;
        },

        isSetKeyboardOpen(matchIndex, setIndex) {
            return this.editingSetCell && this.editingSetCell.matchIndex === matchIndex && this.editingSetCell.setIndex === setIndex;
        },
        openSetKeyboard(matchIndex, setIndex) {
            if (this.isSetInputDisabled(matchIndex, setIndex)) return;
            this.editingSetCell = { matchIndex, setIndex };
        },
        closeSetKeyboard() {
            this.editingSetCell = null;
        },
        setKeyboardKey(char) {
            if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return;
            const { matchIndex, setIndex } = this.editingSetCell;
            const sets = this.results[matchIndex].sets || [];
            const current = sets[setIndex] || '';
            if (current.length >= 6) return;
            this.results[matchIndex].sets[setIndex] = current + char;
            this.broadcastDraftDebounced();
        },
        setKeyboardBackspace() {
            if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return;
            const { matchIndex, setIndex } = this.editingSetCell;
            const sets = this.results[matchIndex].sets || [];
            const current = sets[setIndex] || '';
            this.results[matchIndex].sets[setIndex] = current.slice(0, -1);
            this.broadcastDraftDebounced();
        },
        setKeyboardClear() {
            if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return;
            const { matchIndex, setIndex } = this.editingSetCell;
            if (!this.results[matchIndex].sets) {
                this.$set(this.results[matchIndex], 'sets', ['', '', '', '', '']);
            }
            this.results[matchIndex].sets[setIndex] = '';
            this.broadcastDraftDebounced();
        },
        setKeyboardOk() {
            if (!this.editingSetCell) return;
            const { matchIndex, setIndex } = this.editingSetCell;
            this.processScoreInput(matchIndex, setIndex);
            this.closeSetKeyboard();
        },
        reopenMatch(idx) {
            const m = this.results[idx];
            m.completed = false;
            m.result = '1:0';
            this.broadcastDraftDebounced();
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(800);
        },
        async loadClubSettings() {
            try {
                const clubId = this.$store.getters.currentClub;
                if (!clubId) return;
                const resp = await apiClient.get(`/clubs/${clubId}`);
                this.clubSettings = resp.data;
            } catch (e) {
                // still, no hard error for dialog
                this.clubSettings = null;
            }
        },
        formatPlayers(team) {
            if (!this.meetingDetails) return '';
            const key = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
            const list = (this.meetingDetails[key] || []).filter(p => p && p.isSelected);
            if (list.length === 0) return '';
            const formatName = (p) => {
                const first = (p.firstName || p.firstname || p.first_name || '').toString().trim();
                const last = (p.lastName || p.lastname || p.last_name || '').toString().trim();
                let name = [first, last].filter(Boolean).join(' ').trim();
                if (!name && p.displayName) name = p.displayName;
                return name || '';
            };
            const singles = list.map(formatName).filter(Boolean);
            return this.joinNatural(singles);
        },

        formatDoubles(team) {
            if (!this.meetingDetails) return '';
            const key = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
            const list = (this.meetingDetails[key] || []).filter(p => p && p.isSelected && p.positionDouble);
            if (list.length === 0) return '';

            const nameOf = (p) => {
                const first = (p.firstName || p.firstname || p.first_name || '').toString().trim();
                const last = (p.lastName || p.lastname || p.last_name || '').toString().trim();
                return [first, last].filter(Boolean).join(' ').trim() || (p.displayName || '').trim();
            };

            const groups = list.reduce((acc, p) => {
                const k = String(p.positionDouble);
                if (!acc[k]) acc[k] = [];
                acc[k].push(p);
                return acc;
            }, {});

            const parts = Object.keys(groups).sort().map(k => {
                const arr = groups[k];
                if (arr.length >= 2) {
                    return `${nameOf(arr[0])} mit ${nameOf(arr[1])}`;
                } else if (arr.length === 1) {
                    return `${nameOf(arr[0])} mit —`;
                }
                return '';
            }).filter(Boolean);

            return this.joinNatural(parts);
        },

        joinNatural(items) {
            const arr = (items || []).filter(Boolean);
            if (arr.length === 0) return '';
            if (arr.length === 1) return arr[0];
            return `${arr.slice(0, -1).join(', ')} und ${arr[arr.length - 1]}`;
        },

        openNuscorePage() {
            // Öffne nuscore-Seite in neuem Tab
            const url = `https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list?code=${this.match.code}`;
            window.open(url, '_blank');
        },

        processScoreInput(matchIndex, setIndex) {
            const match = this.results[matchIndex];
            const inputValue = String(match.sets[setIndex] ?? '').trim();

            if (!inputValue) {
                return;
            }

            // Validiere Eingabe: nur Zahlen, Bindestriche und Doppelpunkte
            const validPattern = /^[0-9:\-\s]*$/;
            if (!validPattern.test(inputValue)) {
                const cleanedValue = inputValue.replace(/[^0-9:\-]/g, '');
                match.sets[setIndex] = cleanedValue;
                return;
            }

            // Verarbeite die Eingabe nach den Regeln
            this.parseAndValidateScore(inputValue, matchIndex, setIndex);
            
            // Nach der Verarbeitung: automatisch abschließen, wenn ein Spieler 3 Sätze gewonnen hat
            const updatedMatch = this.results[matchIndex];
            if (updatedMatch && !updatedMatch.completed) {
                const homeWins = this.getPlayerSetWins(updatedMatch, 'home');
                const guestWins = this.getPlayerSetWins(updatedMatch, 'guest');
                
                if (homeWins >= 3 || guestWins >= 3) {
                    this.completeMatch(matchIndex);
                }
            }
            
            // Aktualisiere die Anzeige
            this.$forceUpdate();
            this.broadcastDraftDebounced();
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(300);
        },

        // Berechne gewonnene Sätze für einen Spieler in einem Match
        getPlayerSetWins(match, player) {
            let wins = 0;
            match.sets.forEach(set => {
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    
                    if (player === 'home' && home > guest) {
                        wins++;
                    } else if (player === 'guest' && guest > home) {
                        wins++;
                    }
                }
            });
            return wins;
        },

        // Prüfe ob ein Satz-Input-Feld deaktiviert werden sollte
        isSetInputDisabled(matchIndex, setIndex) {
            const match = this.results[matchIndex];
            
            // Wenn Match bereits abgeschlossen, alle Felder deaktiviert
            if (match.completed) {
                return true;
            }
            
            // Berechne aktuelle Gewinne ohne das zu prüfende Feld
            let homeWins = 0;
            let guestWins = 0;
            
            match.sets.forEach((set, index) => {
                // Überspringe das aktuell zu prüfende Feld
                if (index === setIndex) {
                    return;
                }
                
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    
                    if (home > guest) {
                        homeWins++;
                    } else if (guest > home) {
                        guestWins++;
                    }
                }
            });
            
            // Prüfe ob das aktuelle Feld bereits ausgefüllt ist
            const currentSet = match.sets[setIndex];
            const currentFieldHasValue = currentSet && currentSet.trim() !== '' && currentSet.includes(':');
            
            // Wenn ein Spieler bereits 3 Sätze gewonnen hat UND das aktuelle Feld leer ist,
            // dann dieses Feld deaktivieren (bereits ausgefüllte Felder bleiben aktiv)
            if ((homeWins >= 3 || guestWins >= 3) && !currentFieldHasValue) {
                return true;
            }
            
            return false;
        },

        // Prüfe ob es leere Input-Felder gibt, die nicht am Ende stehen
        hasGapInSets(match) {
            const problematicGaps = [];
            
            for (let i = 0; i < match.sets.length; i++) {
                const hasCurrentValue = match.sets[i] && match.sets[i].trim() !== '' && match.sets[i].includes(':');
                
                // Wenn dieses Feld leer ist, prüfe ob es ein Problem darstellt
                if (!hasCurrentValue) {
                    // Prüfe ob es ausgefüllte Felder nach diesem gibt
                    const hasFilledAfter = match.sets.slice(i + 1).some(set => 
                        set && set.trim() !== '' && set.includes(':')
                    );
                    
                    if (hasFilledAfter) {
                        problematicGaps.push(i);
                    }
                }
            }
            
            return problematicGaps.length > 0 ? problematicGaps : false;
        },

        // Prüfe ob ein Satz-Input rot umrandet werden sollte
        shouldHighlightSetInput(matchIndex, setIndex) {
            const match = this.results[matchIndex];
            
            // Wenn Match schon abgeschlossen, keine Hervorhebung
            if (match.completed) {
                return false;
            }
            
            // Hole alle Lücken-Indizes
            const gapIndices = this.hasGapInSets(match);
            
            if (gapIndices === false) {
                return false;
            }
            
            // Prüfe ob dieses Feld eine der problematischen Lücken ist
            if (Array.isArray(gapIndices) && gapIndices.includes(setIndex)) {
                const currentSet = match.sets[setIndex];
                return !currentSet || currentSet.trim() === '' || !currentSet.includes(':');
            }
            
            return false;
        },

        parseAndValidateScore(inputValue, matchIndex, setIndex) {
            const match = this.results[matchIndex];
            const cleanedValue = String(inputValue ?? '').trim();

            // Prüfe ob das Feld überhaupt bearbeitet werden darf
            if (this.isSetInputDisabled(matchIndex, setIndex)) {
                return;
            }

            // Verschiedene Eingabeformate unterstützen:
            // "3:1", "3-1", "3 1", "3:1 ", "3", "-3"
            let homeScore, guestScore;

            if (cleanedValue.includes(':')) {
                // Format: "3:1" (explizit mit Doppelpunkt)
                const parts = cleanedValue.split(':');
                homeScore = parseInt(parts[0], 10) || 0;
                guestScore = parseInt(parts[1], 10) || 0;
            } else if (cleanedValue.startsWith('-')) {
                // Format: "-8" -> Gast gewinnt 8:11 (Heim hat 8, Gast 11)
                const valueStr = cleanedValue.substring(1).trim();
                const value = parseInt(valueStr, 10) || 0;
                homeScore = value;
                guestScore = Math.max(11, value + 2);
            } else if (/^\d+$/.test(cleanedValue)) {
                // Nur eine positive Zahl: "8" -> Heim gewinnt 11:8 (Gast hat 8 Punkte)
                const value = parseInt(cleanedValue, 10) || 0;
                homeScore = Math.max(11, value + 2);
                guestScore = value;
            } else if (cleanedValue.includes('-') && cleanedValue.split('-').length === 2) {
                // Format: "3-1" (zwei Teile mit Bindestrich)
                const parts = cleanedValue.split('-');
                homeScore = parseInt(parts[0], 10) || 0;
                guestScore = parseInt(parts[1], 10) || 0;
            } else if (cleanedValue.includes(' ')) {
                // Format: "3 1"
                const parts = cleanedValue.split(/\s+/);
                homeScore = parseInt(parts[0], 10) || 0;
                guestScore = parseInt(parts[1], 10) || 0;
            } else {
                // Fallback: wie eine einzelne Zahl behandeln
                const value = parseInt(cleanedValue, 10) || 0;
                homeScore = Math.max(11, value + 2);
                guestScore = value;
            }

            // Umfassende Validierung der Satzergebnisse
            const validationResult = this.validateSetScore(homeScore, guestScore, cleanedValue);
            
            if (!validationResult.isValid) {
                // Bei ungültiger Eingabe: Fehlermeldung speichern und Feld leeren
                this.errors[matchIndex] = validationResult.error;
                match.sets[setIndex] = '';
                return;
            }

            // Bei gültiger Eingabe: Fehlermeldung löschen
            this.clearMatchError(matchIndex);

            // Setze das formatierte Ergebnis zurück
            match.sets[setIndex] = `${homeScore}:${guestScore}`;
            
            // Automatische Berechnung des Gesamtergebnisses
            this.calculateMatchResult(matchIndex);
            
            // Synchronisiere zurück ins Match-Objekt
            this.syncResultsToMatch();
            this.persistLocalDraftDebounced();
            this.broadcastDraftDebounced();
        },

        validateSetScore(homeScore, guestScore, originalInput) {
            // Regel 1: Keine negativen Punkte erlaubt
            if (homeScore < 0 || guestScore < 0) {
                return {
                    isValid: false,
                    error: 'Negative Punkte sind nicht erlaubt'
                };
            }

            // Regel 2: Mindestens ein Spieler muss mindestens 11 Punkte haben
            if (homeScore < 11 && guestScore < 11) {
                return {
                    isValid: false,
                    error: 'Mindestens ein Spieler muss mindestens 11 Punkte haben'
                };
            }

            // Regel 3: Mindestens 2 Punkte Unterschied zwischen den Spielern
            const scoreDifference = Math.abs(homeScore - guestScore);
            if (scoreDifference < 2) {
                return {
                    isValid: false,
                    error: 'Zwischen den Spielern muss mindestens 2 Punkte Unterschied sein'
                };
            }

            // Regel 4: Prüfe auf ungültige Eingabeformate wie "x--y"
            if (originalInput.includes('--') || originalInput.includes('::')) {
                return {
                    isValid: false,
                    error: 'Ungültiges Eingabeformat (doppelte Bindestriche oder Doppelpunkte)'
                };
            }

            // Regel 5: Bei expliziten Formaten (:, -, Leerzeichen) zusätzliche Validierung
            if (originalInput.includes(':') || originalInput.includes('-') || originalInput.includes(' ')) {
                // Bei expliziten Formaten müssen beide Werte sinnvoll sein
                if (homeScore === 0 && guestScore === 0) {
                    return {
                        isValid: false,
                        error: 'Bei expliziter Eingabe dürfen nicht beide Werte 0 sein'
                    };
                }
            }

            // Alle Validierungen bestanden
            return {
                isValid: true,
                error: null
            };
        },

        validateMatchCompletion(matchIndex) {
            const match = this.results[matchIndex];
            
            // Prüfe auf Lücken in der Sätze-Reihenfolge
            const gapIndices = this.hasGapInSets(match);
            if (gapIndices !== false && Array.isArray(gapIndices) && gapIndices.length > 0) {
                const gapNumbers = gapIndices.map(idx => idx + 1).join(', ');
                return {
                    isValid: false,
                    error: `Satz ${gapNumbers} muss ausgefüllt werden, bevor weitere Sätze eingegeben werden können.`
                };
            }
            
            let homeWins = 0;
            let guestWins = 0;
            
            // Zähle gewonnene Sätze
            match.sets.forEach(set => {
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    if (home > guest) {
                        homeWins++;
                    } else if (guest > home) {
                        guestWins++;
                    }
                }
            });
            
            // Regel: Ein Spieler muss genau 3 Sätze gewonnen haben
            if (homeWins !== 3 && guestWins !== 3) {
                return {
                    isValid: false,
                    error: `Ein Spieler muss genau 3 Sätze gewinnen. Aktuell: ${homeWins}:${guestWins}`
                };
            }
            
            return {
                isValid: true,
                error: null
            };
        },

        calculateMatchResult(matchIndex) {
            const match = this.results[matchIndex];
            let homeWins = 0;
            let guestWins = 0;
            
            match.sets.forEach(set => {
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    if (home > guest) {
                        homeWins++;
                    } else if (guest > home) {
                        guestWins++;
                    }
                }
            });
            
            // Setze automatisch das Gesamtergebnis wenn alle Sätze eingegeben sind
            if (homeWins + guestWins === match.sets.length && match.sets.every(s => s && s.includes(':'))) {
                if (homeWins > guestWins) {
                    match.result = '1:0';
                } else if (guestWins > homeWins) {
                    match.result = '0:1';
                }
            }
        },

        getSetRatio(match) {
            let homeWins = 0;
            let guestWins = 0;
            
            match.sets.forEach(set => {
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    if (home > guest) {
                        homeWins++;
                    } else if (guest > home) {
                        guestWins++;
                    }
                }
            });
            
            return `${homeWins}:${guestWins}`;
        },

        getMatchError(matchIndex) {
            return this.errors[matchIndex] || null;
        },

        clearMatchError(matchIndex) {
            this.errors[matchIndex] = null;
        },

        setCurrentStartTime() {
            const now = new Date();
            const timeString = now.toTimeString().slice(0, 5); // HH:MM format
            this.match.startDate = this.createDateTimeFromTimeString(timeString);
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(500);
        },

        setCurrentEndTime() {
            const now = new Date();
            const timeString = now.toTimeString().slice(0, 5); // HH:MM format
            this.match.endDate = this.createDateTimeFromTimeString(timeString);
            
            // Prüfe ob Endzeit vor Startzeit liegt und korrigiere automatisch
            if (this.match.startDate && this.match.endDate) {
                const startTime = new Date(this.match.startDate).getTime();
                const endTime = new Date(this.match.endDate).getTime();
                
                if (endTime <= startTime) {
                    console.log('⚠️ Endzeit liegt vor/auf Startzeit - korrigiere auf nächsten Tag...');
                    // Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
                    const nextDay = new Date(endTime);
                    nextDay.setDate(nextDay.getDate() + 1);
                    this.match.endDate = nextDay;
                    console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
                }
            }
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(500);
        },

        setStartTime(timeString) {
            this.match.startDate = this.createDateTimeFromTimeString(timeString);
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(500);
        },

        setEndTime(timeString) {
            this.match.endDate = this.createDateTimeFromTimeString(timeString);
            
            // Prüfe ob Endzeit vor Startzeit liegt und korrigiere automatisch
            if (this.match.startDate && this.match.endDate) {
                const startTime = new Date(this.match.startDate).getTime();
                const endTime = new Date(this.match.endDate).getTime();
                
                if (endTime <= startTime) {
                    console.log('⚠️ Endzeit liegt vor/auf Startzeit - korrigiere auf nächsten Tag...');
                    // Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
                    const nextDay = new Date(endTime);
                    nextDay.setDate(nextDay.getDate() + 1);
                    this.match.endDate = nextDay;
                    console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
                }
            }
            this.persistLocalDraftDebounced();
            this.syncDraftToServerDebounced(500);
        },

        getFormattedTime(dateValue) {
            if (!dateValue) return '';
            
            const date = new Date(dateValue);
            if (isNaN(date.getTime())) return '';
            
            return date.toTimeString().slice(0, 5); // HH:MM format
        },

        createDateTimeFromTimeString(timeString) {
            if (!timeString) return null;
            
            // Verwende das vorhandene Datum und ergänze die Zeit
            const existingDate = new Date(this.match.startDate || this.match.endDate || new Date());
            const [hours, minutes] = timeString.split(':');
            
            existingDate.setHours(parseInt(hours));
            existingDate.setMinutes(parseInt(minutes));
            existingDate.setSeconds(0);
            existingDate.setMilliseconds(0);
            
            return existingDate;
        },

        getOverallScore() {
            let homeWins = 0;
            let guestWins = 0;
            
            this.results.forEach(match => {
                if (match.completed) {
                    // Zähle gewonnene Sätze für dieses Match
                    let matchHomeWins = 0;
                    let matchGuestWins = 0;
                    
                    match.sets.forEach(set => {
                        if (set && set.includes(':')) {
                            const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                            if (home > guest) {
                                matchHomeWins++;
                            } else if (guest > home) {
                                matchGuestWins++;
                            }
                        }
                    });
                    
                    // Wer hat das Match gewonnen?
                    if (matchHomeWins > matchGuestWins) {
                        homeWins++;
                    } else if (matchGuestWins > matchHomeWins) {
                        guestWins++;
                    }
                }
            });
            
            return `${homeWins}:${guestWins}`;
        },

        getOverallScore() {
            let homeWins = 0;
            let guestWins = 0;
            let totalHomeSetsWon = 0;
            let totalGuestSetsWon = 0;

            this.results.forEach(match => {
                if (match.completed) {
                    // Zähle gewonnene Sätze für dieses Match und Gesamtsätze
                    let matchHomeWins = 0;
                    let matchGuestWins = 0;
                    
                    match.sets.forEach(set => {
                        if (set && set.includes(':')) {
                            const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                            
                            if (home > guest) {
                                matchHomeWins++;
                                totalHomeSetsWon++;
                            } else if (guest > home) {
                                matchGuestWins++;
                                totalGuestSetsWon++;
                            }
                        }
                    });
                    
                    // Wer hat das Match gewonnen?
                    if (matchHomeWins > matchGuestWins) {
                        homeWins++;
                    } else if (matchGuestWins > matchHomeWins) {
                        guestWins++;
                    }
                }
            });
            
            return `${homeWins}:${guestWins} (${totalHomeSetsWon}:${totalGuestSetsWon} Sätze)`;
        },

        getMatchResult(match) {
            // Nur Punkte anzeigen wenn Match abgeschlossen ist
            if (!match.completed) {
                return "—";
            }
            
            let homeWins = 0;
            let guestWins = 0;
            
            match.sets.forEach(set => {
                if (set && set.includes(':')) {
                    const [home, guest] = set.split(':').map(s => parseInt(s) || 0);
                    if (home > guest) {
                        homeWins++;
                    } else if (guest > home) {
                        guestWins++;
                    }
                }
            });
            
            // Match ist abgeschlossen - zeige 1:0 oder 0:1
            if (homeWins > guestWins) {
                return "1:0";
            } else if (guestWins > homeWins) {
                return "0:1";
            } else {
                return "—";
            }
        },

        togglePlayerSelection(player, team) {
            if (this.isLineupLocked(team)) return;
            if (!this.meetingDetails) return;

            const teamKey = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
            const playerIndex = this.meetingDetails[teamKey].findIndex(p => p.nuLigaPersonId === player.nuLigaPersonId);

            if (playerIndex !== -1) {
                // Toggle selection status
                this.meetingDetails[teamKey][playerIndex].isSelected = !this.meetingDetails[teamKey][playerIndex].isSelected;

                // Recalculate all positions for selected players
                this.recalculatePositions(teamKey);

                // Ergebnisse neu berechnen, wenn nicht beide Aufstellungen zertifiziert sind
                if (!this.isHomeLineupCertified || !this.isGuestLineupCertified) {
                    this.prepareResults();
                }

            }
            this.persistLocalDraftDebounced();
            this.broadcastDraftDebounced();
            this.syncDraftToServerDebounced(700);
        },

        toggleDoublePosition(player, team, doublePosition) {
            if (this.isLineupLocked(team)) return;
            if (!this.meetingDetails) return;

            const teamKey = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
            const playerIndex = this.meetingDetails[teamKey].findIndex(p => p.nuLigaPersonId === player.nuLigaPersonId);

            if (playerIndex !== -1) {
                const currentDoublePosition = this.meetingDetails[teamKey][playerIndex].positionDouble;

                if (currentDoublePosition === doublePosition) {
                    // Deselect if already selected
                    this.meetingDetails[teamKey][playerIndex].positionDouble = null;
                } else {
                    // Check if we can select this position
                    if (!this.canSelectDoublePosition(player, team, doublePosition)) {
                        return;
                    }

                    // Select new position (automatically removes from previous position)
                    this.meetingDetails[teamKey][playerIndex].positionDouble = doublePosition;
                    

                    // Ergebnisse neu berechnen, wenn nicht beide Aufstellungen zertifiziert sind
                    if (!this.isHomeLineupCertified || !this.isGuestLineupCertified) {
                        this.prepareResults();
                    }
                }
            }
            this.persistLocalDraftDebounced();
            this.broadcastDraftDebounced();
            this.syncDraftToServerDebounced(700);
        },

        canSelectDoublePosition(player, team, doublePosition) {
            if (!this.meetingDetails) return false;

            const teamKey = team === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';

            // Check if player is already selected for a different double position
            if (player.positionDouble && player.positionDouble !== doublePosition) {
                return false; // Player is already assigned to a different double position
            }

            // Count how many players are already selected for this double position
            // Include ALL players (both selected and available) who have this double position
            const playersInDoublePosition = this.meetingDetails[teamKey].filter(p =>
                p.positionDouble === doublePosition && p.nuLigaPersonId !== player.nuLigaPersonId && p.nuLigaPersonId > 0
            );

            // Allow selection if less than 2 players are already selected for this position
            return playersInDoublePosition.length < 2;
        },

        recalculatePositions(teamKey) {
            if (!this.meetingDetails || !this.meetingDetails[teamKey]) return;

            // Get all selected players and sort by rank
            const selectedPlayers = this.meetingDetails[teamKey].filter(p => p.isSelected && p.nuLigaPersonId > 0);
            const sortedByRank = selectedPlayers.sort((a, b) => a.rank - b.rank);

            // Clear all positions first
            this.meetingDetails[teamKey].forEach(player => {
                if (player.nuLigaPersonId > 0) {
                    player.positions = [];
                    player.positionSingle = null;
                }
            });

            // Assign new positions based on rank
            sortedByRank.forEach((player, index) => {
                const playerIndex = this.meetingDetails[teamKey].findIndex(p => p.nuLigaPersonId === player.nuLigaPersonId);
                if (playerIndex !== -1) {
                    this.meetingDetails[teamKey][playerIndex].positionSingle = index + 1;
                    this.meetingDetails[teamKey][playerIndex].positions = [`E${index + 1}`];
                }
            });
        },

        // PINs automatisch laden
        loadPinsAutomatically() {
            // Heim-PIN nur aus match.homePin übernehmen (echte PIN), niemals aus meetingDetails (Hash)
            if (this.match && this.match.homePin) {
                this.homePin = this.match.homePin;
            } else {
                this.homePin = '';
            }

            // Gast-PIN nur aus match.guestPin übernehmen (falls vorhanden), niemals aus meetingDetails (Hash)
            if (this.match && this.match.guestPin) {
                this.guestPin = this.match.guestPin;
            } else {
                // explizit leeren, falls keine Gast-PIN in der DB existiert
                this.guestPin = '';
            }
        },


        onPinChange(team, event) {
            if (this.isLineupLocked(team)) {
                return;
            }
            const pin = event.target.value;
            if (team === 'home') {
                this.homePin = pin;
            } else {
                this.guestPin = pin;
            }
            this.clearPinFeedback(team);
            this.clearSigningFeedback(team);
            this.persistLocalDraftDebounced();
        },

        pinInputClasses(team) {
            return [
                'pin-input',
                {
                    'pin-input-success': this.pinFeedback[team] === 'success' || this.signingFeedback[team] === 'success',
                    'pin-input-error': this.pinFeedback[team] === 'error' || this.signingFeedback[team] === 'error'
                }
            ];
        },

        signButtonClasses(team) {
            return [
                'sign-btn',
                {
                    'sign-btn-success': this.signingFeedback[team] === 'success',
                    'sign-btn-error': this.signingFeedback[team] === 'error'
                }
            ];
        },

        signButtonLabel(team) {
            if (this.signingFeedback[team] === 'success') {
                return '✅ Signiert!';
            }
            if (this.signingFeedback[team] === 'error') {
                return `✍️ ${this.$t('matchReportApi.signLineup')}`;
            }
            return `✍️ ${this.$t('matchReportApi.signLineup')}`;
        },

        scheduleFeedbackReset(storeName, timerStoreName, team, delay = 3000) {
            if (this[timerStoreName][team]) {
                clearTimeout(this[timerStoreName][team]);
            }
            this[timerStoreName][team] = setTimeout(() => {
                this[storeName][team] = '';
                this[timerStoreName][team] = null;
            }, delay);
        },

        setPinFeedback(team, state) {
            this.pinFeedback[team] = state;
            if (!state) {
                if (this.pinFeedbackTimers[team]) {
                    clearTimeout(this.pinFeedbackTimers[team]);
                    this.pinFeedbackTimers[team] = null;
                }
                return;
            }
            this.scheduleFeedbackReset('pinFeedback', 'pinFeedbackTimers', team);
        },

        clearPinFeedback(team) {
            this.setPinFeedback(team, '');
        },

        setSigningFeedback(team, state) {
            this.signingFeedback[team] = state;
            if (!state) {
                if (this.signingFeedbackTimers[team]) {
                    clearTimeout(this.signingFeedbackTimers[team]);
                    this.signingFeedbackTimers[team] = null;
                }
                return;
            }
            this.scheduleFeedbackReset('signingFeedback', 'signingFeedbackTimers', team);
        },

        clearSigningFeedback(team) {
            this.setSigningFeedback(team, '');
        },

        // Aufstellung signieren
        async signLineup(team) {
            if (this.isLineupLocked(team)) {
                return;
            }
            const pin = team === 'home' ? this.homePin : this.guestPin;

            if (!pin) {
                this.showPinValidation(team, false, 'Keine PIN eingegeben');
                return;
            }

            // PIN validieren
            const isValid = await this.validatePin(team, pin);

            if (isValid) {
                // Aufstellung zertifizieren
                if (team === 'home') {
                    this.setLineupCertificationState('home', true);
                    this.originalHomePin = pin; // Ursprüngliche PIN speichern
                } else {
                    this.setLineupCertificationState('guest', true);
                    this.originalGuestPin = pin; // Ursprüngliche PIN speichern
                }
                
                this.showSigningSuccess(team);
                
                // Intelligente Navigation nach Zertifizierung
                this.navigateAfterCertification();
                
                // Validiere und speichere die Änderungen
                await this.validateReport();
                this.persistLocalDraft();
                this.broadcastDraftDebounced();
                await this.syncDraftToServer();
            } else {
                this.showSigningError(team);
            }
        },

        async hashPinHMAC(pin, key, algorithm = 'SHA-512', encoding = 'utf8') {
            // HMAC-SHA512 Implementierung für Browser
            const encoder = new TextEncoder();
            const pinData = encoder.encode(pin);
            const keyData = encoder.encode(key);

            // Importiere die Web Crypto API für HMAC
            const cryptoKey = await crypto.subtle.importKey(
                'raw',
                keyData,
                { name: 'HMAC', hash: algorithm },
                false,
                ['sign']
            );

            const signature = await crypto.subtle.sign('HMAC', cryptoKey, pinData);
            const hashArray = Array.from(new Uint8Array(signature));
            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        },

        async hashPinWithSalt(pin, algorithm = 'SHA-256', salt = '', encoding = 'utf8') {
            let pinData, saltData;

            if (encoding === 'utf8') {
                const encoder = new TextEncoder();
                pinData = encoder.encode(pin);
                saltData = encoder.encode(salt);
            } else if (encoding === 'ascii') {
                // ASCII-Kodierung
                pinData = new Uint8Array(pin.length);
                for (let i = 0; i < pin.length; i++) {
                    pinData[i] = pin.charCodeAt(i);
                }
                saltData = new Uint8Array(salt.length);
                for (let i = 0; i < salt.length; i++) {
                    saltData[i] = salt.charCodeAt(i);
                }
            } else {
                // Fallback zu UTF-8
                const encoder = new TextEncoder();
                pinData = encoder.encode(pin);
                saltData = encoder.encode(salt);
            }

            // Kombiniere PIN und Salt
            const combinedData = new Uint8Array(pinData.length + saltData.length);
            combinedData.set(pinData);
            combinedData.set(saltData, pinData.length);

            const hashBuffer = await crypto.subtle.digest(algorithm, combinedData);
            const hashArray = Array.from(new Uint8Array(hashBuffer));
            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        },

        async validatePin(team, pin) {
            if (!pin || !this.meetingDetails) return false;

            const expectedHash = team === 'home' ? this.meetingDetails.homePin : this.meetingDetails.guestPin;


            if (!expectedHash) {
                return false;
            }

            try {
                // Hash4096-Validierung (nuscore-Standard)
                if (this.match && this.match.code) {
                    const combined = this.match.code + pin;
                    const hash4096Result = this.hash4096(combined);
                    
                    if (hash4096Result === expectedHash) {
                        this.showPinValidation(team, true, 'Hash4096');
                        return true;
                    }
                }

                this.showPinValidation(team, false);
                return false;

            } catch (error) {
                return false;
            }
        },

        async hashPin(pin, algorithm = 'SHA-256', encoding = 'utf8') {
            let data;

            if (encoding === 'utf8') {
                const encoder = new TextEncoder();
                data = encoder.encode(pin);
            } else if (encoding === 'ascii') {
                // ASCII-Kodierung: Jedes Zeichen als einzelnes Byte
                data = new Uint8Array(pin.length);
                for (let i = 0; i < pin.length; i++) {
                    data[i] = pin.charCodeAt(i);
                }
            } else if (encoding === 'utf16') {
                // UTF-16 Kodierung
                const encoder = new TextEncoder();
                data = encoder.encode(pin);
            } else if (encoding === 'latin1') {
                // Latin-1 Kodierung
                data = new Uint8Array(pin.length);
                for (let i = 0; i < pin.length; i++) {
                    data[i] = pin.charCodeAt(i) & 0xFF;
                }
            } else {
                // Fallback zu UTF-8
                const encoder = new TextEncoder();
                data = encoder.encode(pin);
            }

            console.log(`🔤 ${encoding.toUpperCase()} Bytes für "${pin}":`, Array.from(data).map(b => b.toString(16).padStart(2, '0')).join(' '));

            const hashBuffer = await crypto.subtle.digest(algorithm, data);
            const hashArray = Array.from(new Uint8Array(hashBuffer));
            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        },

        async hashPinHMAC(pin, key, algorithm = 'SHA-512', encoding = 'utf8') {
            // HMAC-SHA512 Implementierung für Browser
            const encoder = new TextEncoder();
            const pinData = encoder.encode(pin);
            const keyData = encoder.encode(key);

            // Importiere die Web Crypto API für HMAC
            const cryptoKey = await crypto.subtle.importKey(
                'raw',
                keyData,
                { name: 'HMAC', hash: algorithm },
                false,
                ['sign']
            );

            const signature = await crypto.subtle.sign('HMAC', cryptoKey, pinData);
            const hashArray = Array.from(new Uint8Array(signature));
            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        },

        showPinValidation(team, isValid, algorithm = null) {
            void algorithm;
            this.setPinFeedback(team, isValid ? 'success' : 'error');
        },

        showSigningSuccess(team) {
            this.setPinFeedback(team, 'success');
            this.setSigningFeedback(team, 'success');
        },

        showSigningError(team) {
            this.setPinFeedback(team, 'error');
            this.setSigningFeedback(team, 'error');
        },

        canSignLineup(team) {
            if (this.isLineupLocked(team)) {
                return false;
            }
            const pin = team === 'home' ? this.homePin : this.guestPin;
            
            // PIN prüfen
            if (!pin || pin.length === 0) {
                return false;
            }
            
            // Mindestspielerzahlen prüfen
            if (!this.hasMinimumPlayerCount(team)) {
                return false;
            }
            
            // Mindestdoppelzahlen prüfen
            if (!this.hasMinimumDoubleCount(team)) {
                return false;
            }
            
            return true;
        },

        // Prüfe Mindestspielerzahlen basierend auf Spielmodus
        hasMinimumPlayerCount(team) {
            const playMode = this.getPlayMode();
            const selectedPlayers = this.getSelectedPlayerCount(team);
            const requiredPlayers = this.getRequiredPlayerCount(playMode);
            
            return selectedPlayers >= requiredPlayers;
        },

        // Prüfe Mindestdoppelzahlen basierend auf Spielmodus
        hasMinimumDoubleCount(team) {
            const playMode = this.getPlayMode();
            const doubleCount = this.getDoubleCount(team);
            const selectedPlayers = this.getSelectedPlayerCount(team);
            const requiredDoubles = this.getMinimumDoubleRequirement(playMode, selectedPlayers);
            
            return doubleCount >= requiredDoubles;
        },

        // Bestimme erforderliche Mindestdoppelzahl basierend auf Spielmodus und Spieleranzahl
        getMinimumDoubleRequirement(playMode, playerCount) {
            const mode = (playMode || '').toLowerCase();
            
            // 6er System
            if (mode.includes('6')) {
                if (playerCount === 6) {
                    return 6; // Alle 6 müssen Doppel spielen
                } else {
                    return 4; // 4-5 Spieler: 4 müssen Doppel spielen
                }
            }
            
            // Braunschweiger System
            if (mode.includes('braunschweiger')) {
                if (playerCount === 2) {
                    return 2; // Beide müssen Doppel spielen
                } else if (playerCount === 3) {
                    return 2; // 2 von 3 müssen Doppel spielen
                } else if (playerCount >= 4) {
                    return 4; // 4 Spieler müssen Doppel spielen (2 Doppel-Paare)
                }
                return 0;
            }
            
            // Andere 4er Systeme (paarkreuz, bundessystem, werner-scheffler, etc.)
            if (mode.includes('4') || mode.includes('paarkreuz') || mode.includes('bundes') || mode.includes('werner')) {
                if (playerCount === 3) {
                    return 2; // 2 von 3 müssen Doppel spielen
                } else if (playerCount >= 4) {
                    return playerCount; // Alle müssen Doppel spielen
                }
                return Math.min(playerCount, 1); // Mindestens 1 Doppel
            }
            
            // 3er System
            if (mode.includes('3')) {
                return Math.min(playerCount, 1); // Mindestens 1 Doppel
            }
            
            // Default: Mindestens 1 Doppel
            return Math.min(playerCount, 1);
        },


        // Zähle Anzahl der Doppel für ein Team
        getDoubleCount(team) {
            try {
                if (team === 'home') {
                    const homePlayers = this.meetingDetails?.teamLineupHomePlayers || this.teamLineupHomePlayers || [];
                    return homePlayers.reduce((count, player) => {
                        return count + (player.positionDouble ? 1 : 0);
                    }, 0);
                } else if (team === 'guest') {
                    const guestPlayers = this.meetingDetails?.teamLineupGuestPlayers || this.teamLineupGuestPlayers || [];
                    return guestPlayers.reduce((count, player) => {
                        return count + (player.positionDouble ? 1 : 0);
                    }, 0);
                }
                return 0;
            } catch (error) {
                console.error('❌ getDoubleCount Fehler:', error);
                return 0;
            }
        },

        formatLineupPositionLabel(position, side) {
            if (typeof position !== 'string') {
                return '';
            }

            const trimmedPosition = position.trim().toUpperCase();
            if (!trimmedPosition) {
                return '';
            }

            if (trimmedPosition.startsWith('D')) {
                return `${side === 'home' ? 'DA' : 'DB'}${trimmedPosition.slice(1)}`;
            }

            if (trimmedPosition.startsWith('E')) {
                return `${side === 'home' ? 'A' : 'B'}${trimmedPosition.slice(1)}`;
            }

            return trimmedPosition;
        },
        getBraunschweigerServerMatrix() {
            const mapFormationsToLabels = (formations) => {
                if (!Array.isArray(formations) || formations.length === 0) {
                    return null;
                }

                return formations
                    .map((formation) => {
                        const homeLabel = this.formatLineupPositionLabel(formation?.homeLineupPosition, 'home');
                        const guestLabel = this.formatLineupPositionLabel(formation?.guestLineupPosition, 'guest');

                        if (homeLabel && guestLabel) {
                            return `${homeLabel} – ${guestLabel}`;
                        }

                        if (typeof formation?.displayString === 'string' && formation.displayString.trim() !== '') {
                            return formation.displayString.trim();
                        }

                        return '';
                    })
                    .filter(Boolean);
            };

            const meetingPlayModeFormations = mapFormationsToLabels(this.meetingDetails?.meetingPlayMode?.matchFormations);
            if (meetingPlayModeFormations && meetingPlayModeFormations.length > 0) {
                return meetingPlayModeFormations;
            }

            const homePlayerCount = this.getEffectivePlayerCount('home');
            const guestPlayerCount = this.getEffectivePlayerCount('guest');
            const optionalMode = Array.isArray(this.meetingDetails?.optionalPlayModes)
                ? this.meetingDetails.optionalPlayModes.find(mode =>
                    Number(mode?.homePlayersCount) === Number(homePlayerCount) &&
                    Number(mode?.guestPlayersCount) === Number(guestPlayerCount) &&
                    Array.isArray(mode?.matchFormations) &&
                    mode.matchFormations.length > 0
                )
                : null;

            return mapFormationsToLabels(optionalMode?.matchFormations);
        },


        // Hole aktuellen Spielmodus (für Validierungen)
        getPlayThrough() {
            // Suche nach playThrough für ALLGAMES-Validierung
            const meetingPlayThrough = this.meetingDetails && this.meetingDetails.playThrough;
            const dataPlayThrough = this.meetingData && this.meetingData.playThrough;
            
            const playThrough = meetingPlayThrough || dataPlayThrough || '';
            console.log(`🔍 getPlayThrough: meetingPlayThrough=${meetingPlayThrough}, dataPlayThrough=${dataPlayThrough}, result=${playThrough}`);
            return playThrough;
        },

        // Hole aktuellen Spielmodus (für matrix/logic)
        getPlayMode() {
            const meetingPlayModeObj = this.meetingDetails && this.meetingDetails.playMode;
            const dataMode = this.meetingData && (this.meetingData.playMode || this.meetingData.matchSystem || this.meetingData.system);
            
            // Falls meetingPlayMode ein Objekt ist, extrahiere die richtige Eigenschaft
            let meetingPlayMode = '';
            if (meetingPlayModeObj) {
                if (typeof meetingPlayModeObj === 'string') {
                    meetingPlayMode = meetingPlayModeObj;
                } else if (meetingPlayModeObj.name) {
                    meetingPlayMode = meetingPlayModeObj.name;
                } else if (meetingPlayModeObj.playMode) {
                    meetingPlayMode = meetingPlayModeObj.playMode;
                } else {
                    // Debug: Objekt-Struktur analysieren
                    console.log('🔍 meetingPlayMode Objekt-Struktur:', Object.keys(meetingPlayModeObj));
                    meetingPlayMode = meetingPlayModeObj.toString();
                }
            }
            
            const playMode = meetingPlayMode || dataMode || '';
            console.log(`🔍 getPlayMode: meetingPlayModeObj=${meetingPlayModeObj}, extracted=${meetingPlayMode}, dataMode=${dataMode}, result=${playMode}`);
            return playMode;
        },

        // Bestimme erforderliche Mindestspielerzahl für Spielmodus
        getRequiredPlayerCount(playMode) {
            if (!playMode) {
                console.log('⚠️ getRequiredPlayerCount: playMode ist undefined oder leer');
                return 3; // Fallback-Wert
            }
            const mode = playMode.toLowerCase();
            
            // 6er System: 4 Spieler erforderlich
            if (mode.includes('6')) {
                return 4;
            }
            
            // 3er System: 2 Spieler erforderlich
            if (mode.includes('3')) {
                return 2;
            }
            
            // Braunschweiger System: 2 Spieler erforderlich
            if (mode.includes('braunschweiger')) {
                return 2;
            }
            
            // Alle anderen 4-Spieler-Systeme: 3 Spieler erforderlich
            // (paarkreuz-system, bundessystem, werner-scheffler-system, etc.)
            return 3;
        },

        // Hole Fehlermeldung für Mindestspielerzahlen und Doppel
        getPlayerCountErrorMessage(team) {
            const playMode = this.getPlayMode();
            const selectedPlayers = this.getSelectedPlayerCount(team);
            const requiredPlayers = this.getRequiredPlayerCount(playMode);
            const doubleCount = this.getDoubleCount(team);
            const requiredDoubles = this.getMinimumDoubleRequirement(playMode, selectedPlayers);
            
            const teamName = team === 'home' ? 'Heim' : 'Gast';
            const playModeName = playMode || 'unbekanntes System';
            
            const errors = [];
            
            // Spielerfehler
            if (selectedPlayers < requiredPlayers) {
                errors.push(`${teamName}team hat nur ${selectedPlayers}/${requiredPlayers} Spieler (${playModeName} benötigt mindestens ${requiredPlayers} Spieler)`);
            }
            
            // Doppelfehler
            if (doubleCount < requiredDoubles) {
                const mode = playMode.toLowerCase();
                let explanation = '';
                
                // Spezielle Erklärungen basierend auf System und Spieleranzahl
                if (mode.includes('6')) {
                    if (selectedPlayers === 6 && requiredDoubles === 6) {
                        explanation = 'alle 6 Spieler müssen Doppel spielen';
                    } else if (requiredDoubles === 4) {
                        explanation = '4 Spieler müssen Doppel spielen';
                    }
                } else if (mode.includes('braunschweiger')) {
                    if (selectedPlayers === 2) {
                        explanation = 'beide Spieler müssen Doppel spielen';
                    } else if (selectedPlayers === 3) {
                        explanation = '2 von 3 Spielern müssen Doppel spielen';
                    } else if (selectedPlayers >= 4 && requiredDoubles === 4) {
                        explanation = '4 Spieler müssen Doppel spielen (2 Doppel-Paare)';
                    }
                } else if (mode.includes('4') || mode.includes('paarkreuz') || mode.includes('bundes') || mode.includes('werner')) {
                    if (selectedPlayers === 3 && requiredDoubles === 2) {
                        explanation = '2 von 3 Spielern müssen Doppel spielen';
                    } else if (requiredDoubles === selectedPlayers) {
                        explanation = `alle ${selectedPlayers} Spieler müssen Doppel spielen`;
                    }
                } else {
                    explanation = `mindestens ${requiredDoubles} Doppel erforderlich`;
                }
                
                errors.push(`${teamName}team hat nur ${doubleCount}/${requiredDoubles} Doppel-spieler (${playModeName} erfordert: ${explanation})`);
            }
            
            if (errors.length === 0) {
                return '';
            }
            
            return `⚠️ ${errors.join(', ')}`;
        },

        // Hash4096 - 4096-mal SHA-512 (wie nuscore verwendet!)
        hash4096(str) {
            let w = CryptoJS.enc.Utf8.parse(str);
            for (let i = 0; i < 4096; i++) {
                w = CryptoJS.SHA512(w);
            }
            return w.toString(CryptoJS.enc.Hex);
        },

        // PIN-Modal für zertifizierte Aufstellungen
        openPinModal(team) {
            this.pinModalTeam = team;
            this.pinModalHomePin = this.originalHomePin || '';
            this.pinModalGuestPin = this.originalGuestPin || '';
            this.pinModalError = '';
            this.showPinModal = true;
        },

        pinModalRequiresHomePin() {
            return this.pinModalTeam === 'homeLineup' || this.pinModalTeam === 'home';
        },

        pinModalRequiresGuestPin() {
            return this.pinModalTeam === 'guestLineup' || this.pinModalTeam === 'guest';
        },

        closePinModal() {
            this.showPinModal = false;
            this.pinModalTeam = null;
            this.pinModalHomePin = '';
            this.pinModalGuestPin = '';
            this.pinModalError = '';
        },

        async submitPinModal() {
            const requiresHomePin = this.pinModalRequiresHomePin();
            const requiresGuestPin = this.pinModalRequiresGuestPin();

            if (requiresHomePin && !this.pinModalHomePin) {
                this.pinModalError = 'Bitte geben Sie die Heim-PIN ein';
                return;
            }

            if (requiresGuestPin && !this.pinModalGuestPin) {
                this.pinModalError = 'Bitte geben Sie die Gast-PIN ein';
                return;
            }

            const homePinValid = !requiresHomePin || await this.validatePin('home', this.pinModalHomePin);
            const guestPinValid = !requiresGuestPin || await this.validatePin('guest', this.pinModalGuestPin);

            if (homePinValid && guestPinValid) {
                console.log('✅ PIN erfolgreich - entsperre Aufstellung und wechsle Tab');
                
                if (requiresHomePin) {
                    this.setLineupCertificationState('home', false);
                }
                if (requiresGuestPin) {
                    this.setLineupCertificationState('guest', false);
                }

                const targetSection = requiresHomePin ? 'homeLineup' : 'guestLineup';
                this.closePinModal();
                this.activeSection = targetSection;
                console.log(`🎯 Wechsle zu ${targetSection}`);
            } else {
                this.pinModalError = requiresHomePin && requiresGuestPin
                    ? 'Eine oder beide PINs sind nicht korrekt'
                    : (requiresHomePin ? 'Die Heim-PIN ist nicht korrekt' : 'Die Gast-PIN ist nicht korrekt');
            }
        },

        isLineupLocked(team) {
            return team === 'home' ? this.isHomeLineupCertified : this.isGuestLineupCertified;
        },

        areBothLineupsCertified() {
            return this.isHomeLineupCertified && this.isGuestLineupCertified;
        },

        // Prüfe ob Aufstellung-Tab geöffnet werden kann
        canOpenLineupTab(team) {
            if ((team === 'home' && this.teamNotAppeared === 'home') ||
                (team === 'guest' && this.teamNotAppeared === 'guest')) {
                return false;
            }

            const isTeamCertified = team === 'home' ? this.isHomeLineupCertified : this.isGuestLineupCertified;

            if (isTeamCertified) {
                return this.areBothLineupsCertified();
            }

            if (team === 'home') {
                return !this.isHomeLineupCertified;
            } else {
                return !this.isGuestLineupCertified;
            }
        },

        // Tab-Wechsel mit PIN-Prüfung
        setActiveSection(section) {
            if ((section === 'homeLineup' && this.teamNotAppeared === 'home') ||
                (section === 'guestLineup' && this.teamNotAppeared === 'guest')) {
                return;
            }

            if (section === 'result' && this.teamNotAppeared !== null) {
                return;
            }

            if (section === 'homeLineup' || section === 'guestLineup') {
                const team = section === 'homeLineup' ? 'home' : 'guest';

                if (!this.canOpenLineupTab(team)) {
                    return;
                }
            }
            
            this.activeSection = section;

            // Gast-PIN beim Öffnen des Gast-Tabs leeren, wenn keine DB-PIN vorhanden ist
            if (section === 'guestLineup' && !(this.match && this.match.guestPin)) {
                this.guestPin = '';
            }
        },

        formatDate(dateString) {
            if (!dateString) return 'N/A';
            const date = new Date(dateString);
            return date.toLocaleDateString('de-DE', {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit',
                hour: '2-digit',
                minute: '2-digit'
            });
        },

        isLikelyPinHash(value) {
            return typeof value === 'string' && /^[a-f0-9]{64,}$/i.test(value.trim());
        }
    }
};
</script>

<style scoped>
.match-report-dialog {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.report-content {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
}

.loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 200px;
}

.spinner {
    width: 40px;
    height: 40px;
    border: 4px solid #f3f3f3;
    border-top: 4px solid var(--primary-color);
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-bottom: 20px;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

.error {
    text-align: center;
    padding: 20px;
}

.retry-btn {
    background-color: var(--primary-color);
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 4px;
    cursor: pointer;
    margin-top: 10px;
}

.retry-btn:hover {
    background-color: var(--primary-hover);
}

.meeting-info {
    max-width: 800px;
    margin: 0 auto;
}

.match-header {
    text-align: center;
    margin-bottom: 30px;
    padding-bottom: 20px;
    border-bottom: 2px solid var(--secondary-color);
}

.match-header h2 {
    color: var(--primary-color);
    margin-bottom: 10px;
    font-size: 1.5em;
}

.match-date {
    display: none;
}

.match-details p {
    margin: 5px 0;
    color: #555;
}

.match-details p:first-child {
    font-weight: bold;
    color: var(--primary-color);
}

.match-stats {
    margin: 30px 0;
}

.team-stats {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: #f8f9fa;
    padding: 20px;
    border-radius: 8px;
}

.home-team,
.guest-team {
    text-align: center;
    flex: 1;
}

.home-team h3,
.guest-team h3 {
    margin: 0 0 10px 0;
    color: var(--primary-color);
}

.points {
    font-size: 2em;
    font-weight: bold;
    color: var(--secondary-color);
}

.vs {
    font-size: 1.5em;
    font-weight: bold;
    color: var(--primary-color);
    margin: 0 20px;
}

.actions {
    display: flex;
    gap: 15px;
    justify-content: center;
    margin-top: 30px;
}

.nuscore-btn,
.copy-btn {
    padding: 12px 24px;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 16px;
    font-weight: 500;
    transition: all 0.3s ease;
}

.nuscore-btn {
    background-color: var(--primary-color);
    color: white;
}

.nuscore-btn:hover {
    background-color: var(--primary-hover);
    transform: translateY(-2px);
}

.copy-btn {
    background-color: var(--secondary-color);
    color: white;
}

.copy-btn:hover {
    background-color: #e02e2b;
    transform: translateY(-2px);
}

/* Nuscore-Style Sektionen */
.nuscore-sections {
    margin: 30px 0;
}

.section-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 8px;
    margin-bottom: 16px;
}

.section-btn {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    background-color: white;
    cursor: pointer;
    transition: all 0.2s ease;
    text-align: center;
    min-height: 36px;
}

.section-btn:hover:not(:disabled) {
    border-color: var(--primary-color);
    background-color: #f8f9fa;
}

.section-btn.active {
    position: relative;
    border-color: var(--primary-color);
    background: #ffffff; /* statt background-color */
    color: var(--primary-color);
}

.section-btn.active::after {
    content: "";
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: -6px;
    height: 3px;
    background: var(--primary-color);
    border-radius: 2px;
}

.section-btn.disabled {
    opacity: 0.6;
    cursor: not-allowed;
    background-color: #f5f5f5;
}

.section-icon {
    font-size: 1.1em;
    margin: 0;
}

.section-btn span {
    font-size: 0.95em;
    font-weight: 600;
}

.section-content {
    min-height: 200px;
    padding: 20px;
    background-color: #f8f9fa;
    border-radius: 8px;
}

.greeting-box {
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    padding: 16px;
    white-space: pre-wrap;
}

.greeting-empty {
    color: #666;
    font-style: italic;
}

.result-content { margin-top: 2px; }
.result-table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; }
.result-table th, .result-table td { border-bottom: 1px solid #eee; padding: 8px; text-align: left; }
.result-table thead th { background: #f8f9fa; }
.set-input-wrapper {
    display: flex;
    align-items: center;
    gap: 4px;
}
.set-input { 
    width: 56px; 
    text-align: center; 
    padding: 6px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
    font-family: monospace;
}

.set-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.2);
}

.set-input:disabled {
    background-color: #f5f5f5;
    color: #999;
    cursor: not-allowed;
}

.set-extra-buttons {
    display: none;
}

.set-extra-btn {
    border: 1px solid #ccc;
    border-radius: 4px;
    background-color: #fff;
    padding: 2px 4px;
    font-size: 0.75rem;
    cursor: pointer;
    line-height: 1;
}

.set-extra-btn:active {
    background-color: #f0f0f0;
}

/* Schwebende Satz-Tastatur (ersetzt System-Tastatur) */
.set-keyboard-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: flex-end;
    justify-content: center;
    z-index: 10000;
    padding: 0;
}
.set-keyboard {
    background: #f0f0f0;
    border-radius: 12px 12px 0 0;
    padding: 12px;
    padding-bottom: max(12px, env(safe-area-inset-bottom));
    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
    width: 100%;
    max-width: 360px;
}
.set-keyboard-value {
    text-align: center;
    font-size: 1.1rem;
    font-family: monospace;
    padding: 4px 10px;
    margin-bottom: 6px;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 8px;
    min-height: 24px;
    line-height: 1.3;
}
.set-keyboard-value.placeholder {
    color: #999;
}
.set-keyboard-keys {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}
.set-key {
    min-height: 48px;
    font-size: 1.25rem;
    border: 1px solid #bbb;
    border-radius: 8px;
    background: #fff;
    color: #333;
    cursor: pointer;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.set-key:active {
    background: #e0e0e0;
}
.set-key-backspace,
.set-key-clear {
    font-size: 1.1rem;
    color: #c62828;
    border-color: #c62828;
}
.set-key-backspace:active,
.set-key-clear:active {
    background: #ffebee;
}
.set-key-ok {
    background: var(--primary-color, #1976d2);
    color: #fff;
    border-color: var(--primary-hover, #1565c0);
    font-weight: 600;
}
.set-key-ok:active {
    opacity: 0.9;
}
.set-input.keyboard-open {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(var(--primary-rgb, 25, 118, 210), 0.3);
}

/* Mobile-spezifische Optimierungen */
@media (max-width: 768px) {
    .set-input {
        width: 58px;
        padding: 8px;
        font-size: 16px; /* Verhindert Zoom auf iOS */
        -webkit-appearance: none;
        appearance: none;
        border-radius: 6px;
    }
}
.state-cell { text-align: center; }
.state-content { display: flex; flex-direction: row; align-items: center; gap: 8px; }
.set-ratio { font-weight: bold; font-size: 14px; color: var(--primary-color); }
.state-btn { 
    border: 1px solid #ccc; 
    border-radius: 4px; 
    padding: 4px 8px; 
    background: #fff; 
    cursor: pointer; 
    font-size: 16px; 
    color: #333; 
    font-weight: bold;
    min-width: 24px;
    min-height: 24px;
}
.state-btn:hover { 
    background: #f1f1f1; 
    border-color: var(--primary-color);
}
/* Spielstand-Anzeige */
.score-summary {
    text-align: center;
    margin: 16px 0;
    padding: 8px;
    background: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 6px;
}

.score-display {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.score-label {
    font-size: 14px;
    font-weight: 500;
    color: #6c757d;
}

.score-value {
    font-size: 16px;
    font-weight: 600;
    color: var(--primary-color);
    font-family: 'Courier New', monospace;
}

.match-result { 
    font-weight: bold; 
    font-size: 16px; 
    text-align: center;
    color: var(--primary-color);
}

/* Zeitfelder */
.time-input-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

.time-input {
    padding: 6px 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
    font-family: monospace;
    background: #fff;
    min-width: 100px;
}

.time-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.2);
}

.time-btn {
    padding: 6px 10px;
    background: #f8f9fa;
    border: 1px solid #ddd;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    transition: background-color 0.2s;
}

.time-btn:hover {
    background: #e9ecef;
    border-color: var(--primary-color);
}

/* Abschluss-Seite */
.lineups-summary {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 15px;
    margin-bottom: 20px;
    padding: 12px;
    background: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 6px;
}

.lineup-team {
    background: #fff;
    padding: 10px;
    border-radius: 4px;
    border: 1px solid #dee2e6;
}

.lineup-team h4 {
    margin: 0 0 8px 0;
    color: var(--primary-color);
    text-align: center;
    font-size: 16px;
}

.doppel-section, .einzel-section {
    margin-bottom: 8px;
}

.doppel-section h5, .einzel-section h5 {
    margin: 0 0 4px 0;
    color: #495057;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.pair-row, .player-row {
    padding: 2px 0;
    font-size: 13px;
    color: #495057;
}

.team-divider {
    display: flex;
    align-items: center;

    justify-content: center;
    font-weight: bold;
    color: var(--primary-color);
    font-size: 16px;
}

.final-score {
    text-align: center;
    margin: 16px 0;
}

.final-score h3 {
    margin: 0 0 8px 0;
    color: var(--primary-color);
    font-size: 18px;
}

.score-summary.large {
    padding: 10px;
    background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
    border: 2px solid var(--primary-color);
    border-radius: 6px;
}

.score-summary.large .score-value {
    font-size: 20px;
    font-weight: bold;
}

.time-summary {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
    margin-bottom: 16px;
    padding: 10px;
    background: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 4px;
}

.time-display {
    display: flex;
    align-items: center;
    gap: 8px;
}

.time-display label {
    font-weight: 500;
    color: #495057;
}

.time-value {
    font-family: 'Courier New', monospace;
    font-weight: 600;
    color: var(--primary-color);
}

.protest-section {
    margin-bottom: 16px;
}

.protest-section label {
    display: block;
    margin-bottom: 4px;
    font-weight: 500;
    color: #495057;
    font-size: 14px;
}

.protest-input {
    width: 100%;
    min-height: 50px;
    padding: 8px;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    font-family: inherit;
    font-size: 13px;
    resize: vertical;
}

.protest-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.2);
}

.final-pins {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
    margin-bottom: 16px;
    padding: 10px;
    background: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 4px;
}

.pin-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.pin-group label {
    font-weight: 500;
    color: #495057;
    font-size: 14px;
}

.pin-not-required {
    font-size: 12px;
    color: #6c757d;
    font-style: italic;
    margin-top: 4px;
}

.submit-section {
    text-align: center;
    padding: 16px;
}

.draft-status-bar {
    border-top: 1px solid var(--border-color);
    padding: 0.5rem 0.9rem;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    background: var(--surface-color);
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-muted);
    min-height: 36px;
}

.draft-status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #6b7280;
    flex: 0 0 auto;
}

.draft-status-bar.state-syncing {
    color: #1d4ed8;
}

.draft-status-bar.state-syncing .draft-status-dot {
    background: #2563eb;
}

.draft-status-bar.state-saved {
    color: #047857;
}

.draft-status-bar.state-saved .draft-status-dot {
    background: #059669;
}

.draft-status-bar.state-fallback {
    color: #b45309;
}

.draft-status-bar.state-fallback .draft-status-dot {
    background: #d97706;
}

.submit-btn {
    font-size: 16px;
    padding: 12px 24px;
    font-weight: 600;
}

/* Fehlermeldungen */
.error-row {
    background-color: #fff5f5;
}

.error-cell {
    padding: 8px 16px !important;
    border-top: none !important;
}

.error-message {
    color: #dc3545;
    font-size: 14px;
    font-weight: 500;
    padding: 4px 8px;
    background-color: #f8d7da;
    border: 1px solid #f5c6cb;
    border-radius: 4px;
    text-align: center;
}

.match-info-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    margin-top: 20px;
}

.info-item {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.info-item label {
    font-weight: bold;
    color: var(--primary-color);
}

.not-appeared-select {
    padding: 8px 12px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
    background-color: white;
    cursor: pointer;
    transition: all 0.3s ease;
}

.not-appeared-select.not-appeared {
    background-color: #fff3cd;
    border-color: #ffc107;
    color: #856404;
    font-weight: 600;
}

.not-appeared-select:hover {
    border-color: #999;
}

.not-appeared-select.not-appeared:hover {
    border-color: #ff9800;
    background-color: #ffe082;
}

.code-display {
    display: flex;
    align-items: center;
    gap: 10px;
}

.code-value {
    font-family: monospace;
    background-color: white;
    padding: 5px 10px;
    border-radius: 4px;
    border: 1px solid #ddd;
}

.code-display .copy-btn {
    padding: 5px 10px;
    border: none;
    border-radius: 4px;
    background-color: var(--secondary-color);
    color: white;
    cursor: pointer;
    font-size: 0.9em;
}

.code-display .copy-btn:hover {
    background-color: #e02e2b;
}

.completed {
    color: #f59e0b;
    font-weight: bold;
}

.pending {
    color: #ffc107;
    font-weight: bold;
}

/* Aufstellungs-Sektionen */
.lineup-content h3 {
    color: var(--primary-color);
    margin-bottom: 20px;
    text-align: center;
}

.players-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 15px;
    margin-top: 20px;
}

.player-card {
    background-color: white;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    transition: all 0.3s ease;
    display: flex;
    flex-direction: row;
    gap: 10px;
    align-items: stretch;
}

.player-card:hover {
    border-color: var(--primary-color);
    box-shadow: 0 2px 8px rgba(74, 140, 190, 0.1);
}

.player-name {
    font-weight: bold;
    font-size: 1.1em;
    color: var(--primary-color);
    margin-bottom: 8px;
}

.player-details {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.player-rank {
    color: #666;
    font-size: 0.9em;
}

.player-position {
    color: var(--secondary-color);
    font-weight: 500;
    font-size: 0.9em;
}

/* Lineup-Sektionen */
.lineup-section {
    margin-bottom: 30px;
}

.lineup-section h4 {
    color: var(--primary-color);
    margin: 20px 0 15px 0;
    font-size: 1.1em;
    border-bottom: 1px solid #e0e0e0;
    padding-bottom: 8px;
}

.player-card.selected {
    border-color: var(--primary-color);
    background-color: #f8f9fa;
}

.player-card.selected .player-name {
    color: var(--primary-color);
}

.player-card.available {
    border-color: #ccc;
    background-color: white;
}

.player-card.available>div:first-child {
    flex: 1;
    cursor: pointer;
    transition: all 0.2s ease;
    padding: 12px;
}

.player-card.available>div:first-child:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.player-card.available>div:first-child:active {
    transform: translateY(0);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.player-card.available .player-name {
    color: #666;
}

.player-card.available:hover {
    border-color: var(--secondary-color);
    background-color: #f8f9fa;
}

/* Klickbare Spielerkarten für verfügbare Spieler - jetzt oben definiert */

.player-action {
    margin-top: 8px;
    font-size: 0.8em;
    color: #666;
    font-style: italic;
    text-align: center;
}

.player-card.selected .player-action {
    color: var(--primary-color);
}

.player-card.available .player-action {
    color: var(--secondary-color);
}

/* Doppel-Auswahl - Layout bereits oben definiert */

.player-main {
    flex: 1;
    cursor: pointer;
    transition: all 0.2s ease;
    padding: 12px;
}

.player-main:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.player-main:active {
    transform: translateY(0);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.double-selection {
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 80px;
    min-width: 80px;
}

.double-btn {
    flex: 1;
    padding: 8px 4px;
    border: 2px solid #28a745;
    background: white;
    color: #28a745;
    border-radius: 6px;
    font-size: 0.9em;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s ease;
    text-align: center;
    min-height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.double-btn:hover:not(:disabled) {
    background-color: rgba(40, 167, 69, 0.1);
    transform: translateY(-1px);
}

.double-btn:active:not(:disabled) {
    transform: translateY(0);
}

.double-btn.active {
    background-color: var(--primary-color);
    color: white;
    border-color: white;
}

.double-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: #f8f9fa;
    color: #6c757d;
    border-color: #dee2e6;
}

.double-btn:disabled:hover {
    transform: none;
    background-color: #f8f9fa;
}

.double-position {
    color: #28a745;
    font-weight: 600;
}

/* PIN-Eingabe Sektionen */
.pin-section {
    margin-bottom: 30px;
    padding: 20px;
    background-color: white;
    border-radius: 8px;
    border: 1px solid #e0e0e0;
}

.pin-section h4 {
    color: var(--primary-color);
    margin: 0 0 15px 0;
    font-size: 1.1em;
    border-bottom: 1px solid #e0e0e0;
    padding-bottom: 8px;
}

.pin-input-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.pin-input-group label {
    font-weight: bold;
    color: var(--primary-color);
    font-size: 0.9em;
}

.pin-input-wrapper {
    display: flex;
    gap: 10px;
    align-items: center;
}

.pin-input {
    flex: 1;
    padding: 10px 12px;
    border: 2px solid #e0e0e0;
    border-radius: 6px;
    font-size: 1em;
    transition: border-color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
}

.pin-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(74, 140, 190, 0.1);
}

.pin-input-success {
    border-color: var(--success-color);
    background-color: rgba(46, 125, 50, 0.12);
}

.pin-input-error {
    border-color: var(--danger-color);
    background-color: rgba(180, 66, 66, 0.12);
}

.load-pin-btn {
    padding: 10px 16px;
    background-color: var(--secondary-color);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9em;
    font-weight: 500;
    transition: all 0.3s ease;
    white-space: nowrap;
}

.load-pin-btn:hover:not(:disabled) {
    background-color: #e02e2b;
    transform: translateY(-1px);
}

.load-pin-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: #6c757d;
}

.load-pin-btn:disabled:hover {
    transform: none;
    background-color: #6c757d;
}

.sign-btn {
    padding: 10px 16px;
    background-color: var(--primary-color);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9em;
    font-weight: 500;
    transition: all 0.3s ease;
    white-space: nowrap;
}

.sign-btn-success {
    background-color: var(--success-color);
}

.sign-btn-error {
    background-color: var(--danger-color);
}

.sign-btn:hover:not(:disabled) {
    background-color: var(--primary-hover);
    transform: translateY(-1px);
}

.sign-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: #6c757d;
}

.sign-btn:disabled:hover {
    transform: none;
    background-color: #6c757d;
}

/* Fehlermeldung bei PIN-Eingabe */
.pin-error-message {
    margin-top: 8px;
    padding: 8px 12px;
    background-color: #fee;
    border: 1px solid #fcc;
    border-radius: 4px;
    color: #c33;
    font-size: 14px;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Satz-Input Warnung für Lücken */
.set-input.gap-warning {
    border: 2px solid #dc3545 !important;
    background-color: #fef5f5 !important;
    box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
}

.set-input.gap-warning:focus {
    border: 2px solid #dc3545 !important;
    box-shadow: 0 0 0 0.3rem rgba(220, 53, 69, 0.25) !important;
}

.set-input:disabled {
    opacity: 0.6 !important;
    cursor: not-allowed !important;
    background-color: #f8f9fa !important;
    border-color: #dee2e6 !important;
}

/* Zertifizierung-Styles */
.section-btn.certified {
    background-color: #d4edda;
    border-color: var(--primary-color);
    color: #155724;
}

.certified-badge {
    font-size: 0.8em;
    background-color: var(--primary-color);
    color: white;
    padding: 0 6px;
    border-radius: 10px;
    margin-left: 8px;
}

.completed-badge {
    font-size: 0.8em;
    padding: 0 6px;
    border-radius: 10px;
    margin-left: 8px;
}

/* PIN-Modal Styles */
.pin-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.pin-modal {
    background: white;
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    max-width: 500px;
    width: 90%;
    max-height: 80vh;
    overflow-y: auto;
}

.pin-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
    border-bottom: 1px solid #e0e0e0;
}

.pin-modal-header h3 {
    margin: 0;
    color: #333;
}

.pin-modal-close {
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: #666;
    padding: 0;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.pin-modal-close:hover {
    color: #333;
}

.pin-modal-body {
    padding: 20px;
}

.pin-modal-inputs {
    margin: 20px 0;
}

.pin-input-group {
    margin-bottom: 15px;
}

.pin-input-group label {
    display: block;
    margin-bottom: 5px;
    font-weight: 500;
    color: #333;
}

.pin-input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 16px;
}

.pin-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}

.pin-hint {
    display: block;
    margin-top: 5px;
    color: #666;
    font-size: 0.9em;
    font-style: italic;
}

/* Match Data Dialog Styles */
.match-data-dialog-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 10000;
    padding: 20px;
    box-sizing: border-box;
}

.match-data-dialog {
    background: white;
    border-radius: 12px;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
    max-width: 90vw;
    max-height: 90vh;
    width: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.match-data-dialog-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid #e0e0e0;
    background: #f8f9fa;
}

.match-data-dialog-header h3 {
    margin: 0;
    color: #333;
    font-size: 18px;
}

.close-dialog-btn {
    background: none;
    border: none;
    font-size: 20px;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    color: #666;
    transition: all 0.2s;
}

.close-dialog-btn:hover {
    background: #e0e0e0;
    color: #333;
}

.match-data-dialog-content {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    padding: 20px;
}

.json-display {
    background: #f8f9fa;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    padding: 16px;
    margin: 0 0 16px 0;
    overflow: auto;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    font-size: 12px;
    line-height: 1.4;
    color: #333;
    white-space: pre-wrap;
    word-wrap: break-word;
    max-height: 60vh;
    flex: 1;
}

.copy-json-btn {
    background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
    color: var(--text-on-primary);
    border: 1px solid transparent;
    padding: 10px 20px;
    border-radius: 10px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 600;
    transition: all 0.2s;
    align-self: flex-start;
}

.copy-json-btn:hover {
    opacity: 0.95;
    transform: translateY(-1px);
}

.copy-json-btn:active {
    transform: translateY(0);
}

/* Deaktivierte Zustände für abgeschlossene Matches */
.submit-btn.disabled {
    background-color: #6c757d;
    color: white;
    cursor: not-allowed;
    opacity: 0.7;
}

.submit-btn.disabled:hover {
    background-color: #6c757d;
    transform: none;
}

.completion-notice {
    margin-top: 8px;
    padding: 8px 12px;
    background-color: #fff3cd;
    border: 1px solid #ffeaa7;
    border-radius: 4px;
    color: #856404;
    font-size: 12px;
    text-align: center;
}

.validation-notice {
    margin-top: 8px;
    padding: 8px 12px;
    background-color: #f8d7da;
    border: 1px solid #f5c6cb;
    border-radius: 4px;
    color: #721c24;
    font-size: 12px;
    text-align: center;
    font-weight: 500;
}

.validation-notice strong {
    color: #721c24;
}

.time-input:disabled,
.protest-input:disabled,
.pin-input:disabled {
    background-color: #f8f9fa;
    color: #6c757d;
    cursor: not-allowed;
    opacity: 0.7;
}

.time-btn:disabled {
    background-color: #f8f9fa;
    color: #6c757d;
    cursor: not-allowed;
    opacity: 0.7;
}

.time-btn:disabled:hover {
    background-color: #f8f9fa;
    transform: none;
}

/* Locked indicator für deaktivierte Tabs */
.locked-indicator {
    margin-left: 8px;
    font-size: 12px;
    opacity: 0.7;
}

/* Begrüßungs-Header */
.greeting-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}

.greeting-header h3 {
    margin: 0;
}

.completion-toggle-btn {
    background: transparent;
    color: #6b7280;
    border: 2px solid #d1d5db;
    padding: 8px 16px;
    border-radius: 8px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 14px;
}

.completion-toggle-btn:hover:not(.completed) {
    background: #f3f4f6;
    border-color: #9ca3af;
}

.completion-toggle-btn.completed {
    background: transparent;
    color: #f59e0b;
    border-color: #f59e0b;
}

.completion-toggle-btn.completed:hover {
    background: #fef3c7;
    color: #f59e0b;
}

/* Ergebniserfassungs-Header */
.result-header {
    margin-bottom: 20px;
}

.result-header h3 {
    margin: 0 0 15px 0;
}

.time-display {
    background-color: #f8f9fa;
    border-radius: 6px;
}

.time-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
}

.time-row:last-child {
    margin-bottom: 0;
}

.time-row strong {
    min-width: 60px;
    color: #495057;
}

.time-btn-small {
    background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
    color: var(--text-on-primary);
    border: 1px solid transparent;
    padding: 4px 8px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s ease;
}

.time-btn-small:hover:not(:disabled) {
    transform: translateY(-1px);
}

.time-btn-small:disabled {
    background-color: #6c757d;
    color: #fff;
    cursor: not-allowed;
}

.result-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.time-btn {
    background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
    color: var(--text-on-primary);
    border: 1px solid transparent;
    padding: 8px 16px;
    border-radius: 10px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: 13px;
    display: flex;
    align-items: center;
    gap: 6px;
}

.time-btn:hover:not(:disabled) {
    transform: translateY(-1px);
}

.time-btn:disabled {
    background: #e5e7eb;
    color: #9ca3af;
    cursor: not-allowed;
    transform: none;
}

.autofill-btn {
    background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
    color: var(--text-on-primary);
    border: 1px solid transparent;
    padding: 12px 20px;
    border-radius: 10px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: all 0.3s ease;
    font-size: 14px;
    box-shadow: 0 8px 18px rgba(47, 122, 95, 0.18);
}

.autofill-btn:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 12px 24px rgba(47, 122, 95, 0.24);
}

.autofill-btn:disabled {
    background: #e2e8f0;
    color: #a0aec0;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

.autofill-section {
    margin: 20px 0;
    display: flex;
    justify-content: center;
}

.endtime-section {
    margin-top: 20px;
    margin-bottom: 0;
}

/* Completion warning auf Ergebniserfassungs-Seite */
.completion-warning {
    display: flex;
    align-items: center;
    padding: 16px;
    margin-bottom: 20px;
    background-color: #fff3cd;
    border: 1px solid #ffeaa7;
    border-radius: 8px;
    color: #856404;
}

.warning-icon {
    font-size: 24px;
    margin-right: 12px;
    flex-shrink: 0;
}

.warning-text {
    flex: 1;
    font-size: 14px;
    line-height: 1.4;
}

.warning-text strong {
    display: block;
    margin-bottom: 4px;
    font-size: 15px;
}

.pin-modal-error {
    color: #8b3327;
    background-color: rgba(200, 74, 56, 0.12);
    border: 1px solid rgba(200, 74, 56, 0.24);
    border-radius: 10px;
    padding: 10px;
    margin-top: 10px;
}

.pin-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 20px;
    border-top: 1px solid #e0e0e0;
}

.btn-secondary {
    background: var(--surface-color);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    padding: 10px 20px;
    border-radius: 10px;
    cursor: pointer;
    font-weight: 600;
}

.btn-secondary:hover {
    background: var(--surface-muted);
    border-color: var(--primary-soft);
}

.btn-primary {
    background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
    color: var(--text-on-primary);
    border: 1px solid transparent;
    padding: 10px 20px;
    border-radius: 10px;
    cursor: pointer;
    font-weight: 600;
}

.btn-primary:hover {
    opacity: 0.95;
}
</style>
