<template>
    <div class="tab-content" key="config-tab">
        <div class="config-grid">
            <section class="config-card">
                <div class="config-card-header">
                    <h4>{{ $t('tournaments.tabConfig') }}</h4>
                    <div class="config-summary-chips">
                        <span class="config-chip">{{ tournamentClasses.length }} {{ $t('tournaments.classes') }}</span>
                        <span class="config-chip">{{ isGroupTournament ? $t('tournaments.tabGroups') : $t('tournaments.tabResults') }}</span>
                    </div>
                </div>
                <div class="tournament-info">
                    <label>
                        {{ $t('tournaments.name') }}:
                        <input type="text" :value="tournamentName" @input="$emit('update:tournamentName', $event.target.value)" />
                    </label>
                    <label>
                        {{ $t('tournaments.date') }}:
                        <input type="date" :value="tournamentDate" @change="$emit('update:tournamentDate', $event.target.value)" />
                    </label>
                    <label>
                        {{ $t('tournaments.winningSets') }}:
                        <input type="number" :value="winningSets" @input="$emit('update:winningSets', parseInt($event.target.value))" min="1" />
                    </label>
                    <label>
                        {{ $t('tournaments.numberOfTables') }}:
                        <input type="number" :value="numberOfTables" @input="$emit('update:numberOfTables', $event.target.value === '' ? null : parseInt($event.target.value))" min="1" placeholder="–" />
                    </label>
                </div>
                <div class="config-actions">
                    <label class="checkbox-item">
                        <input type="checkbox" :checked="isGroupTournament" @change="$emit('update:isGroupTournament', $event.target.checked)" />
                        <span>{{ $t('tournaments.playInGroups') }}</span>
                    </label>
                    <button @click="$emit('generate-pdf')" class="btn-primary">{{ $t('tournaments.exportPDF') }}</button>
                </div>
            </section>

            <section class="config-card">
                <div class="config-card-header">
                    <h4>{{ $t('tournaments.classes') }}</h4>
                    <span class="config-chip">{{ tournamentClasses.length }}</span>
                </div>
                <TournamentClassList
                    :tournament-classes="tournamentClasses"
                    :show-classes="showClasses"
                    :editing-class-id="editingClassId"
                    :editing-class-name="editingClassName"
                    :editing-class-is-doubles="editingClassIsDoubles"
                    :editing-class-gender="editingClassGender"
                    :editing-class-min-birth-year="editingClassMinBirthYear"
                    :new-class-name="newClassName"
                    :new-class-is-doubles="newClassIsDoubles"
                    :new-class-gender="newClassGender"
                    :new-class-min-birth-year="newClassMinBirthYear"
                    @edit-class="$emit('edit-class', $event)"
                    @save-class-edit="$emit('save-class-edit', $event)"
                    @cancel-class-edit="$emit('cancel-class-edit')"
                    @delete-class="$emit('delete-class', $event)"
                    @add-class="(data) => $emit('add-class', data)"
                    @add-class-error="$emit('add-class-error', $event)"
                    @handle-class-input-blur="$emit('handle-class-input-blur', $event[0], $event[1])"
                    @update:editingClassName="$emit('update:editingClassName', $event)"
                    @update:editingClassIsDoubles="$emit('update:editingClassIsDoubles', $event)"
                    @update:editingClassGender="$emit('update:editingClassGender', $event)"
                    @update:editingClassMinBirthYear="$emit('update:editingClassMinBirthYear', $event)"
                    @update:newClassName="$emit('update:newClassName', $event)"
                    @update:newClassIsDoubles="$emit('update:newClassIsDoubles', $event)"
                    @update:newClassGender="$emit('update:newClassGender', $event)"
                    @update:newClassMinBirthYear="$emit('update:newClassMinBirthYear', $event)"
                />
            </section>
        </div>

        <details v-if="!isMiniChampionship" class="stage-config" style="margin-top: 1.5rem;">
            <summary class="stage-config-summary">{{ $t('tournaments.stageConfigTitle') }}</summary>
            <div v-if="stageConfig.loading" style="opacity: 0.8;">
                {{ $t('tournaments.stageConfigLoading') }}
            </div>
            <div v-else>
                <p class="stage-config-intro">
                    {{ $t('tournaments.stageConfigIntro') }}
                </p>
                <div class="stage-config-summary-box">
                    <strong>{{ $t('tournaments.stageConfigCurrentSetup') }}</strong>
                    <span>{{ stageFlowSummary }}</span>
                </div>
                <div class="stage-flow-health" :class="`stage-flow-health--${stageFlowHealth.level}`">
                    <strong>{{ stageFlowHealth.label }}</strong>
                    <span>{{ stageFlowHealth.message }}</span>
                    <button
                        v-if="autoFixableStageIssues.length > 0"
                        type="button"
                        class="stage-flow-health-action"
                        @click="applyAllStageQuickFixes"
                    >
                        {{ $t('tournaments.stageValidationApplyAllFixes', { count: autoFixableStageIssues.length }) }}
                    </button>
                </div>
                <div v-if="stageFlowRecommendation" class="stage-flow-recommendation">
                    <div class="stage-flow-recommendation-copy">
                        <strong>{{ $t('tournaments.stageFlowRecommendationTitle') }}</strong>
                        <span>{{ stageFlowRecommendation.message }}</span>
                    </div>
                    <button type="button" class="btn-primary" @click="runStageFlowRecommendation">
                        {{ stageFlowRecommendation.label }}
                    </button>
                </div>
                <div v-if="stageFlowPreviewItems.length > 0" class="stage-flow-preview-list">
                    <div v-for="item in stageFlowPreviewItems" :key="item.key" class="stage-flow-preview-item">
                        <strong>{{ item.label }}</strong>
                        <span>{{ item.message }}</span>
                    </div>
                </div>
                <div class="stage-flow-breakdown">
                    <button
                        v-for="item in stageFlowBreakdown"
                        :key="item.key"
                        type="button"
                        class="stage-flow-breakdown-item"
                        :class="`stage-flow-breakdown-item--${item.level}`"
                        @click="handleStageFlowBreakdownClick(item)"
                    >
                        <strong>{{ item.label }}</strong>
                        <span>{{ item.message }}</span>
                        <em class="stage-flow-breakdown-action">{{ item.actionLabel }}</em>
                    </button>
                </div>
                <div v-if="stageValidationIssues.length > 0" class="stage-validation-list">
                    <div class="stage-validation-header">
                        <strong>{{ $t('tournaments.stageValidationTitle') }}</strong>
                        <span>{{ $t('tournaments.stageValidationDescription') }}</span>
                    </div>
                    <div
                        v-for="issue in stageValidationIssues"
                        :key="issue.key"
                        class="stage-validation-item"
                        :class="`stage-validation-item--${issue.level}`"
                        :role="issue.fields?.length ? 'button' : undefined"
                        :tabindex="issue.fields?.length ? 0 : undefined"
                        @click="focusStageField(issue.fields?.[0])"
                        @keydown.enter.prevent="focusStageField(issue.fields?.[0])"
                        @keydown.space.prevent="focusStageField(issue.fields?.[0])"
                    >
                        <strong>{{ issue.title }}</strong>
                        <span>{{ issue.message }}</span>
                    </div>
                </div>

                <div class="stage-config-layout">
                    <section class="stage-card">
                        <div class="stage-card-step">{{ $t('tournaments.stageStep1') }}</div>
                        <strong>{{ $t('tournaments.stageStep1Title') }}</strong>
                        <p class="stage-card-copy">{{ $t('tournaments.stageStep1Description') }}</p>
                        <label class="checkbox-item" style="margin: 0.25rem 0;">
                        <input type="checkbox" v-model="stageConfig.useIntermediateStage" />
                        <span>{{ $t('tournaments.useIntermediateStage') }}</span>
                        </label>
                    </section>

                    <section v-if="stageConfig.useIntermediateStage" class="stage-card">
                        <div class="stage-card-step">{{ $t('tournaments.stageStep2') }}</div>
                        <strong>{{ $t('tournaments.intermediateRound') }}</strong>
                        <p class="stage-card-copy">{{ $t('tournaments.stageStep2Description') }}</p>
                        <div class="stage-field-grid">
                            <label>
                                {{ $t('tournaments.roundMode') }}:
                                <select v-model="stageConfig.stage2Type">
                                    <option value="groups">{{ $t('tournaments.groupsLabel') }}</option>
                                    <option value="knockout">{{ $t('tournaments.knockoutLabel') }}</option>
                                </select>
                            </label>

                            <label v-if="stageConfig.stage2Type === 'groups'">
                                {{ $t('tournaments.roundGroupCount') }}:
                                <input
                                    type="number"
                                    min="1"
                                    v-model.number="stageConfig.stage2GroupCount"
                                    :class="{ 'field-invalid': hasStageFieldError('stage2-group-count') }"
                                    data-field-key="stage2-group-count"
                                />
                                <div v-if="getStageFieldHint('stage2-group-count')" class="field-inline-hint field-inline-hint--error">
                                    {{ getStageFieldHint('stage2-group-count') }}
                                </div>
                            </label>
                        </div>

                        <div class="pool-config">
                            <div class="pool-config-header">
                                <div>
                                    <strong>{{ $t('tournaments.promotionRule12') }}</strong>
                                    <div class="pool-config-copy">{{ $t('tournaments.promotionRuleDescription12') }}</div>
                                </div>
                                <button class="btn-secondary" @click="addPoolRule('12')" type="button">{{ $t('tournaments.addPoolRule') }}</button>
                            </div>
                            <div v-if="stageConfig.pools12.length === 0" class="pool-config-empty">
                                {{ $t('tournaments.noPoolRulesYet12') }}
                            </div>
                            <div v-for="(rule, idx) in stageConfig.pools12" :key="`12-${idx}`" class="pool-rule" :data-rule-key="`stage2:${idx}`">
                                <div class="pool-rule-heading">
                                    <strong>{{ $t('tournaments.poolRuleLabel', { number: idx + 1 }) }}</strong>
                                    <span class="pool-rule-summary">
                                        {{ $t('tournaments.poolRuleSummary', {
                                            places: rule.fromPlacesText || '–',
                                            target: rule.targetType === 'knockout'
                                                ? $t('tournaments.knockoutLabel')
                                                : $t('tournaments.targetGroupsLabel', { count: rule.targetGroupCount || stageConfig.stage2GroupCount || 2 })
                                        }) }}
                                    </span>
                                    <span class="pool-rule-preview">
                                        {{ poolRulePreview(rule, 'stage2') }}
                                    </span>
                                    <div class="pool-rule-status" :class="`pool-rule-status--${getRuleStatus('stage2', idx).level}`">
                                        <strong>{{ getRuleStatusLabel('stage2', idx) }}</strong>
                                        <span>{{ getRuleStatusMessage('stage2', idx) }}</span>
                                    </div>
                                    <div v-if="getRuleQualifiedPreview('stage2', rule).length > 0" class="pool-rule-qualified">
                                        <strong>{{ $t('tournaments.stageFlowQualifiedPreviewTitle') }}</strong>
                                        <div class="pool-rule-qualified-list">
                                            <span
                                                v-for="participant in getRuleQualifiedPreview('stage2', rule)"
                                                :key="participant.key"
                                                class="pool-rule-qualified-chip"
                                            >
                                                {{ participant.label }}
                                            </span>
                                        </div>
                                    </div>
                                </div>
                                <label :class="{ 'field-invalid-label': hasRuleFieldError('stage2', idx, 'places') }">
                                    {{ $t('tournaments.poolRulePlacesLabel') }}:
                                    <input
                                        type="text"
                                        v-model="rule.fromPlacesText"
                                        :class="{ 'field-invalid': hasRuleFieldError('stage2', idx, 'places') }"
                                        :data-field-key="`stage2:${idx}:places`"
                                    />
                                    <div v-if="getRuleFieldHint('stage2', idx, 'places')" class="field-inline-hint field-inline-hint--error">
                                        {{ getRuleFieldHint('stage2', idx, 'places') }}
                                    </div>
                                    <div v-if="getRulePlacesSuggestion('stage2', idx)" class="field-inline-hint field-inline-hint--hint">
                                        {{ $t('tournaments.stageValidationSuggestion', { value: getRulePlacesSuggestion('stage2', idx) }) }}
                                    </div>
                                    <button
                                        v-if="getRulePlacesSuggestion('stage2', idx)"
                                        type="button"
                                        class="field-fix-button"
                                        @click="applyRulePlacesSuggestion('stage2', idx)"
                                    >
                                        {{ $t('tournaments.stageValidationApplyFix') }}
                                    </button>
                                </label>
                                <div class="pool-rule-help">{{ $t('tournaments.poolRulePlacesHelp') }}</div>

                                <div class="pool-rule-targets">
                                    <label :class="{ 'field-invalid-label': hasRuleFieldError('stage2', idx, 'targetType') }">
                                        {{ $t('tournaments.poolRuleTargetLabel') }}:
                                        <select
                                            v-model="rule.targetType"
                                            :class="{ 'field-invalid': hasRuleFieldError('stage2', idx, 'targetType') }"
                                            :data-field-key="`stage2:${idx}:targetType`"
                                        >
                                            <option value="groups">{{ $t('tournaments.groupsLabel') }}</option>
                                            <option value="knockout">{{ $t('tournaments.knockoutLabel') }}</option>
                                        </select>
                                        <div v-if="getRuleFieldHint('stage2', idx, 'targetType')" class="field-inline-hint field-inline-hint--error">
                                            {{ getRuleFieldHint('stage2', idx, 'targetType') }}
                                        </div>
                                        <button
                                            v-if="hasRuleQuickFix('stage2', idx, 'targetType')"
                                            type="button"
                                            class="field-fix-button"
                                            @click="applyRuleQuickFix('stage2', idx, 'targetType')"
                                        >
                                            {{ getRuleQuickFixLabel('stage2', idx, 'targetType') }}
                                        </button>
                                    </label>
                                    <label v-if="rule.targetType === 'groups'" :class="{ 'field-invalid-label': hasRuleFieldError('stage2', idx, 'targetGroupCount') }">
                                        {{ $t('tournaments.targetGroupCount') }}:
                                        <input
                                            type="number"
                                            min="1"
                                            v-model.number="rule.targetGroupCount"
                                            :class="{ 'field-invalid': hasRuleFieldError('stage2', idx, 'targetGroupCount') }"
                                            :data-field-key="`stage2:${idx}:targetGroupCount`"
                                        />
                                        <div v-if="getRuleFieldHint('stage2', idx, 'targetGroupCount')" class="field-inline-hint field-inline-hint--error">
                                            {{ getRuleFieldHint('stage2', idx, 'targetGroupCount') }}
                                        </div>
                                        <button
                                            v-if="hasRuleQuickFix('stage2', idx, 'targetGroupCount')"
                                            type="button"
                                            class="field-fix-button"
                                            @click="applyRuleQuickFix('stage2', idx, 'targetGroupCount')"
                                        >
                                            {{ getRuleQuickFixLabel('stage2', idx, 'targetGroupCount') }}
                                        </button>
                                    </label>
                                    <button class="btn-danger" type="button" @click="removePoolRule(idx)">{{ $t('common.delete') }}</button>
                                </div>
                            </div>
                            <div v-if="stageConfig.pools12.length > 0" class="pool-rule-presets">
                                <span>{{ $t('tournaments.poolRuleQuickExamples') }}</span>
                                <button type="button" class="pool-rule-preset" @click="applyPresetRule(stageConfig.pools12[stageConfig.pools12.length - 1], '1,2')">1,2</button>
                                <button type="button" class="pool-rule-preset" @click="applyPresetRule(stageConfig.pools12[stageConfig.pools12.length - 1], '1')">1</button>
                            </div>
                        </div>
                    </section>

                    <section class="stage-card">
                        <div class="stage-card-step">{{ stageConfig.useIntermediateStage ? $t('tournaments.stageStep3') : $t('tournaments.stageStep2') }}</div>
                        <strong>{{ $t('tournaments.finalRound') }}</strong>
                        <p class="stage-card-copy">{{ $t('tournaments.stageFinalDescription') }}</p>
                        <div class="stage-field-grid">
                            <label>
                                {{ $t('tournaments.roundMode') }}:
                                <select v-model="stageConfig.finalStageType">
                                    <option value="groups">{{ $t('tournaments.groupsLabel') }}</option>
                                    <option value="knockout">{{ $t('tournaments.knockoutLabel') }}</option>
                                </select>
                            </label>
                            <label v-if="stageConfig.finalStageType === 'groups'">
                                {{ $t('tournaments.roundGroupCount') }}:
                                <input
                                    type="number"
                                    min="1"
                                    v-model.number="stageConfig.finalStageGroupCount"
                                    :class="{ 'field-invalid': hasStageFieldError('final-group-count') }"
                                    data-field-key="final-group-count"
                                />
                                <div v-if="getStageFieldHint('final-group-count')" class="field-inline-hint field-inline-hint--error">
                                    {{ getStageFieldHint('final-group-count') }}
                                </div>
                            </label>
                        </div>
                        <label v-if="stageConfig.finalStageType === 'knockout'" class="stage-third-place">
                            <input
                                type="checkbox"
                                :checked="stageConfig.finalStageThirdPlace"
                                @change="onThirdPlaceToggle($event.target.checked)"
                                @click.stop
                            />
                            {{ $t('tournaments.playThirdPlace') }}
                        </label>

                        <div class="pool-config">
                            <div class="pool-config-header">
                                <div>
                                    <strong>{{ $t('tournaments.promotionRuleFinal', { from: stageConfig.useIntermediateStage ? 2 : 1, to: stageConfig.useIntermediateStage ? 3 : 3 }) }}</strong>
                                    <div class="pool-config-copy">
                                        {{ stageConfig.finalStageType === 'knockout' ? $t('tournaments.promotionRuleDescriptionFinalKnockout') : $t('tournaments.promotionRuleDescriptionFinalGroups') }}
                                    </div>
                                </div>
                                <button class="btn-secondary" @click="addPoolRule('final')" type="button">{{ $t('tournaments.addPoolRule') }}</button>
                            </div>
                            <div v-if="finalPools.length === 0" class="pool-config-empty">
                                {{ $t('tournaments.noPoolRulesYetFinal') }}
                            </div>
                            <div v-for="(rule, idx) in finalPools" :key="`final-${idx}`" class="pool-rule" :data-rule-key="`final:${idx}`">
                                <div class="pool-rule-heading">
                                    <strong>{{ $t('tournaments.poolRuleLabel', { number: idx + 1 }) }}</strong>
                                    <span class="pool-rule-summary">
                                        {{ $t('tournaments.poolRuleSummary', {
                                            places: rule.fromPlacesText || '–',
                                            target: stageConfig.finalStageType === 'knockout'
                                                ? $t('tournaments.knockoutLabel')
                                                : $t('tournaments.targetGroupsLabel', { count: rule.targetGroupCount || stageConfig.finalStageGroupCount || 1 })
                                        }) }}
                                    </span>
                                    <span class="pool-rule-preview">
                                        {{ poolRulePreview(rule, 'final') }}
                                    </span>
                                    <div class="pool-rule-status" :class="`pool-rule-status--${getRuleStatus('final', idx).level}`">
                                        <strong>{{ getRuleStatusLabel('final', idx) }}</strong>
                                        <span>{{ getRuleStatusMessage('final', idx) }}</span>
                                    </div>
                                    <div v-if="getRuleQualifiedPreview('final', rule).length > 0" class="pool-rule-qualified">
                                        <strong>{{ $t('tournaments.stageFlowQualifiedPreviewTitle') }}</strong>
                                        <div class="pool-rule-qualified-list">
                                            <span
                                                v-for="participant in getRuleQualifiedPreview('final', rule)"
                                                :key="participant.key"
                                                class="pool-rule-qualified-chip"
                                            >
                                                {{ participant.label }}
                                            </span>
                                        </div>
                                    </div>
                                </div>
                                <label :class="{ 'field-invalid-label': hasRuleFieldError('final', idx, 'places') }">
                                    {{ $t('tournaments.poolRulePlacesLabel') }}:
                                    <input
                                        type="text"
                                        v-model="rule.fromPlacesText"
                                        :class="{ 'field-invalid': hasRuleFieldError('final', idx, 'places') }"
                                        :data-field-key="`final:${idx}:places`"
                                    />
                                    <div v-if="getRuleFieldHint('final', idx, 'places')" class="field-inline-hint field-inline-hint--error">
                                        {{ getRuleFieldHint('final', idx, 'places') }}
                                    </div>
                                    <div v-if="getRulePlacesSuggestion('final', idx)" class="field-inline-hint field-inline-hint--hint">
                                        {{ $t('tournaments.stageValidationSuggestion', { value: getRulePlacesSuggestion('final', idx) }) }}
                                    </div>
                                    <button
                                        v-if="getRulePlacesSuggestion('final', idx)"
                                        type="button"
                                        class="field-fix-button"
                                        @click="applyRulePlacesSuggestion('final', idx)"
                                    >
                                        {{ $t('tournaments.stageValidationApplyFix') }}
                                    </button>
                                </label>
                                <div class="pool-rule-help">{{ $t('tournaments.poolRulePlacesHelp') }}</div>
                                <div class="pool-rule-targets">
                                    <label :class="{ 'field-invalid-label': hasRuleFieldError('final', idx, 'targetType') }">
                                        {{ $t('tournaments.poolRuleTargetLabel') }}:
                                        <select
                                            v-model="rule.targetType"
                                            :disabled="stageConfig.finalStageType !== 'groups'"
                                            :class="{ 'field-invalid': hasRuleFieldError('final', idx, 'targetType') }"
                                            :data-field-key="`final:${idx}:targetType`"
                                        >
                                            <option value="groups">{{ $t('tournaments.groupsLabel') }}</option>
                                            <option value="knockout">{{ $t('tournaments.knockoutLabel') }}</option>
                                        </select>
                                        <div v-if="getRuleFieldHint('final', idx, 'targetType')" class="field-inline-hint field-inline-hint--error">
                                            {{ getRuleFieldHint('final', idx, 'targetType') }}
                                        </div>
                                        <button
                                            v-if="hasRuleQuickFix('final', idx, 'targetType')"
                                            type="button"
                                            class="field-fix-button"
                                            @click="applyRuleQuickFix('final', idx, 'targetType')"
                                        >
                                            {{ getRuleQuickFixLabel('final', idx, 'targetType') }}
                                        </button>
                                    </label>
                                    <label v-if="stageConfig.finalStageType === 'groups'" :class="{ 'field-invalid-label': hasRuleFieldError('final', idx, 'targetGroupCount') }">
                                        {{ $t('tournaments.targetGroupCount') }}:
                                        <input
                                            type="number"
                                            min="1"
                                            v-model.number="rule.targetGroupCount"
                                            :class="{ 'field-invalid': hasRuleFieldError('final', idx, 'targetGroupCount') }"
                                            :data-field-key="`final:${idx}:targetGroupCount`"
                                        />
                                        <div v-if="getRuleFieldHint('final', idx, 'targetGroupCount')" class="field-inline-hint field-inline-hint--error">
                                            {{ getRuleFieldHint('final', idx, 'targetGroupCount') }}
                                        </div>
                                        <button
                                            v-if="hasRuleQuickFix('final', idx, 'targetGroupCount')"
                                            type="button"
                                            class="field-fix-button"
                                            @click="applyRuleQuickFix('final', idx, 'targetGroupCount')"
                                        >
                                            {{ getRuleQuickFixLabel('final', idx, 'targetGroupCount') }}
                                        </button>
                                    </label>
                                    <button class="btn-danger" type="button" @click="removePoolRule(idx, 'final')">{{ $t('common.delete') }}</button>
                                </div>
                            </div>
                            <div v-if="finalPools.length > 0" class="pool-rule-presets">
                                <span>{{ $t('tournaments.poolRuleQuickExamples') }}</span>
                                <button type="button" class="pool-rule-preset" @click="applyPresetRule(finalPools[finalPools.length - 1], '1,2')">1,2</button>
                                <button type="button" class="pool-rule-preset" @click="applyPresetRule(finalPools[finalPools.length - 1], '1')">1</button>
                            </div>
                        </div>
                    </section>

                    <div class="stage-actions-panel">
                        <div class="stage-actions-header">
                            <strong>{{ $t('tournaments.stageActionsTitle') }}</strong>
                            <span>{{ $t('tournaments.stageActionsDescription') }}</span>
                        </div>
                        <div class="stage-actions">
                            <button class="btn-primary" type="button" :disabled="hasBlockingStageValidationIssues" @click="onSaveClick">{{ $t('tournaments.saveRounds') }}</button>
                        </div>
                        <div class="stage-action-list">
                            <div v-if="!stageConfig.useIntermediateStage" class="stage-action-item">
                                <div class="stage-action-copy">
                                    <strong>{{ $t('tournaments.transferQualifiedToFinalFromPreliminary') }}</strong>
                                    <span>{{ $t('tournaments.transferQualifiedToFinalFromPreliminaryDesc') }}</span>
                                </div>
                                <button
                                    class="btn-secondary"
                                    type="button"
                                    :disabled="!canAdvanceToFinalFromPreliminary || hasBlockingStageValidationIssues"
                                    @click="advanceStage(1, 3)"
                                >
                                    {{ $t('tournaments.stageActionRun') }}
                                </button>
                            </div>
                            <div v-else class="stage-action-item">
                                <div class="stage-action-copy">
                                    <strong>{{ $t('tournaments.transferQualifiedToIntermediate') }}</strong>
                                    <span>{{ $t('tournaments.transferQualifiedToIntermediateDesc') }}</span>
                                </div>
                                <button
                                    class="btn-secondary"
                                    type="button"
                                    :disabled="!canAdvanceToIntermediate || hasBlockingStageValidationIssues"
                                    @click="advanceStage(1, 2)"
                                >
                                    {{ $t('tournaments.stageActionRun') }}
                                </button>
                            </div>
                            <div v-if="stageConfig.useIntermediateStage" class="stage-action-item">
                                <div class="stage-action-copy">
                                    <strong>{{ $t('tournaments.transferQualifiedToFinalFromIntermediate') }}</strong>
                                    <span>{{ $t('tournaments.transferQualifiedToFinalFromIntermediateDesc') }}</span>
                                </div>
                                <button
                                    class="btn-secondary"
                                    type="button"
                                    :disabled="!canAdvanceToFinalFromIntermediate || hasBlockingStageValidationIssues"
                                    @click="advanceStage(2, 3)"
                                >
                                    {{ $t('tournaments.stageActionRun') }}
                                </button>
                            </div>
                        </div>
                        <div v-if="!hasAnyAdvanceRule" class="stage-actions-hint">
                            {{ $t('tournaments.stageActionMissingRulesHint') }}
                        </div>
                    </div>
                    <div v-if="stageConfig.error" class="stage-message-error">
                        {{ stageConfig.error }}
                    </div>
                    <div v-if="stageConfig.success" class="stage-message-success">
                        {{ stageConfig.success }}
                    </div>
                </div>
            </div>
        </details>
    </div>
</template>

<script>
import TournamentClassList from './TournamentClassList.vue';
import apiClient from '../../apiClient';

export default {
    name: 'TournamentConfigTab',
    components: {
        TournamentClassList
    },
    props: {
        clubId: {
            type: [Number, String],
            required: true
        },
        tournamentId: {
            type: [Number, String],
            required: true
        },
        tournamentName: {
            type: String,
            required: true
        },
        tournamentDate: {
            type: String,
            required: true
        },
        winningSets: {
            type: Number,
            required: true
        },
        numberOfTables: {
            type: [Number, null],
            default: null
        },
        isGroupTournament: {
            type: Boolean,
            required: true
        },
        groups: {
            type: Array,
            default: () => []
        },
        groupMatches: {
            type: Array,
            default: () => []
        },
        plannedGroupCount: {
            type: [Number, null],
            default: null
        },
        isMiniChampionship: {
            type: Boolean,
            default: false
        },
        tournamentClasses: {
            type: Array,
            required: true
        },
        showClasses: {
            type: Boolean,
            default: false
        },
        editingClassId: {
            type: [Number, null],
            default: null
        },
        editingClassName: {
            type: String,
            default: ''
        },
        editingClassIsDoubles: {
            type: Boolean,
            default: false
        },
        editingClassGender: {
            type: [String, null],
            default: null
        },
        editingClassMinBirthYear: {
            type: [Number, null],
            default: null
        },
        newClassName: {
            type: String,
            default: ''
        },
        newClassIsDoubles: {
            type: Boolean,
            default: false
        },
        newClassGender: {
            type: [String, null],
            default: null
        },
        newClassMinBirthYear: {
            type: [Number, null],
            default: null
        }
    },
    data() {
        return {
            stageConfig: {
                loading: false,
                useIntermediateStage: true,
                stage2Type: 'groups',
                stage2GroupCount: 2,
                pools12: [],
                poolsFinal: [],
                stage2StageId: null,
                finalStageId: null,
                finalStageType: 'knockout',
                finalStageThirdPlace: false,
                finalStageGroupCount: 1,
                error: null,
                success: null,
            },
            highlightedRuleElement: null,
            highlightedRuleTimer: null,
        };
    },
    computed: {
        finalPools() {
            return this.stageConfig.poolsFinal;
        },
        canAdvanceToIntermediate() {
            return this.stageConfig.useIntermediateStage && this.stageConfig.pools12.length > 0;
        },
        canAdvanceToFinalFromPreliminary() {
            return !this.stageConfig.useIntermediateStage && this.finalPools.length > 0;
        },
        canAdvanceToFinalFromIntermediate() {
            return this.stageConfig.useIntermediateStage && this.finalPools.length > 0;
        },
        hasAnyAdvanceRule() {
            return this.stageConfig.pools12.length > 0 || this.finalPools.length > 0;
        },
        stageValidationIssues() {
            const issues = [];
            const stage2Label = this.$t('tournaments.intermediateRound');
            const finalLabel = this.$t('tournaments.finalRound');
            const pushIssues = (items) => {
                items.forEach((item, index) => {
                    issues.push({
                        ...item,
                        key: item.key || `${item.transition}-${index}-${item.code}`
                    });
                });
            };

            if (
                this.stageConfig.useIntermediateStage &&
                this.stageConfig.stage2Type === 'groups' &&
                (!Number.isFinite(Number(this.stageConfig.stage2GroupCount)) || Number(this.stageConfig.stage2GroupCount) < 1)
            ) {
                issues.push({
                    key: 'stage2-group-count',
                    level: 'error',
                    title: stage2Label,
                    message: this.$t('tournaments.stageValidationGroupCountRequired'),
                    fields: ['stage2-group-count']
                });
            }

            if (
                this.stageConfig.finalStageType === 'groups' &&
                (!Number.isFinite(Number(this.stageConfig.finalStageGroupCount)) || Number(this.stageConfig.finalStageGroupCount) < 1)
            ) {
                issues.push({
                    key: 'final-group-count',
                    level: 'error',
                    title: finalLabel,
                    message: this.$t('tournaments.stageValidationGroupCountRequired'),
                    fields: ['final-group-count']
                });
            }

            if (this.stageConfig.useIntermediateStage) {
                pushIssues(this.validatePoolRules(this.stageConfig.pools12, {
                    stageLabel: stage2Label,
                    transition: 'stage2',
                    forceKnockout: false,
                    allowGroupsTarget: true,
                    expectedTargetType: this.stageConfig.stage2Type,
                    expectedGroupCount: this.stageConfig.stage2Type === 'groups'
                        ? Number(this.stageConfig.stage2GroupCount || 0)
                        : null
                }));
            }

            pushIssues(this.validatePoolRules(this.finalPools, {
                stageLabel: finalLabel,
                transition: 'final',
                forceKnockout: this.stageConfig.finalStageType === 'knockout',
                allowGroupsTarget: this.stageConfig.finalStageType === 'groups',
                expectedTargetType: this.stageConfig.finalStageType,
                expectedGroupCount: this.stageConfig.finalStageType === 'groups'
                    ? Number(this.stageConfig.finalStageGroupCount || 0)
                    : null
            }));

            return issues;
        },
        stageFlowHealth() {
            const errors = this.stageValidationIssues.filter(issue => issue.level === 'error');
            const warnings = this.stageValidationIssues.filter(issue => issue.level === 'warning');
            const hasIntermediateRules = !this.stageConfig.useIntermediateStage || this.stageConfig.pools12.length > 0;
            const hasFinalRules = this.finalPools.length > 0;
            const hasRulesForAllTransitions = hasIntermediateRules && hasFinalRules;

            if (errors.length > 0) {
                return {
                    level: 'error',
                    label: this.$t('tournaments.stageFlowHealthBlocked'),
                    message: this.$t('tournaments.stageFlowHealthBlockedDescription')
                };
            }

            if (!hasRulesForAllTransitions || warnings.length > 0) {
                return {
                    level: 'warning',
                    label: this.$t('tournaments.stageFlowHealthIncomplete'),
                    message: !hasRulesForAllTransitions
                        ? this.$t('tournaments.stageFlowHealthMissingRules')
                        : this.$t('tournaments.stageFlowHealthReviewDescription')
                };
            }

            return {
                level: 'ok',
                label: this.$t('tournaments.stageFlowHealthOk'),
                message: this.$t('tournaments.stageFlowHealthOkDescription')
            };
        },
        stageFlowBreakdown() {
            const items = [];
            const buildItem = ({ key, label, transition, enabled, missingRuleMessage }) => {
                if (!enabled) return null;
                const transitionIssues = this.stageValidationIssues.filter(issue => issue.transition === transition);
                const errorCount = transitionIssues.filter(issue => issue.level === 'error').length;
                const warningCount = transitionIssues.filter(issue => issue.level === 'warning').length;
                const firstIssue = transitionIssues[0] || null;
                const hasRules = transition === 'stage2' ? this.stageConfig.pools12.length > 0 : this.finalPools.length > 0;
                const readiness = this.getTransitionReadiness(transition);
                const focusField = firstIssue?.fields?.[0]
                    || (transition === 'stage2' ? 'stage2:0:places' : 'final:0:places');

                if (!hasRules) {
                    return {
                        key,
                        label,
                        level: 'warning',
                        message: missingRuleMessage,
                        focusField,
                        action: 'add-rule',
                        actionLabel: this.$t('tournaments.stageFlowBreakdownActionAddRule')
                    };
                }
                if (!readiness.ready) {
                    return {
                        key,
                        label,
                        level: 'warning',
                        message: readiness.message,
                        focusField,
                        action: 'review',
                        actionLabel: this.$t('tournaments.stageFlowBreakdownActionReview')
                    };
                }
                if (errorCount > 0) {
                    return {
                        key,
                        label,
                        level: 'error',
                        message: this.$t('tournaments.stageFlowBreakdownErrors', { count: errorCount }),
                        focusField,
                        action: 'review',
                        actionLabel: this.$t('tournaments.stageFlowBreakdownActionReview')
                    };
                }
                if (warningCount > 0) {
                    return {
                        key,
                        label,
                        level: 'warning',
                        message: this.$t('tournaments.stageFlowBreakdownWarnings', { count: warningCount }),
                        focusField,
                        action: 'review',
                        actionLabel: this.$t('tournaments.stageFlowBreakdownActionReview')
                    };
                }
                return {
                    key,
                    label,
                    level: 'ok',
                    message: this.$t('tournaments.stageFlowBreakdownOk'),
                    focusField,
                    action: 'open',
                    actionLabel: this.$t('tournaments.stageFlowBreakdownActionOpen')
                };
            };

            if (this.stageConfig.useIntermediateStage) {
                items.push(buildItem({
                    key: 'stage2',
                    label: this.$t('tournaments.promotionRule12'),
                    transition: 'stage2',
                    enabled: true,
                    missingRuleMessage: this.$t('tournaments.stageFlowBreakdownMissingRule')
                }));
                items.push(buildItem({
                    key: 'final',
                    label: this.$t('tournaments.promotionRuleFinal', { from: 2, to: 3 }),
                    transition: 'final',
                    enabled: true,
                    missingRuleMessage: this.$t('tournaments.stageFlowBreakdownMissingRule')
                }));
            } else {
                items.push(buildItem({
                    key: 'final',
                    label: this.$t('tournaments.promotionRuleFinal', { from: 1, to: 3 }),
                    transition: 'final',
                    enabled: true,
                    missingRuleMessage: this.$t('tournaments.stageFlowBreakdownMissingRule')
                }));
            }

            return items.filter(Boolean);
        },
        autoFixableStageIssues() {
            const fixes = [];
            const collectRuleFixes = (transition, rules) => {
                rules.forEach((rule, index) => {
                    const placesSuggestion = this.getRulePlacesSuggestion(transition, index);
                    if (placesSuggestion) {
                        fixes.push({ type: 'places', transition, index });
                    }
                    ['targetType', 'targetGroupCount'].forEach(field => {
                        if (this.hasRuleQuickFix(transition, index, field)) {
                            fixes.push({ type: field, transition, index });
                        }
                    });
                });
            };
            collectRuleFixes('stage2', this.stageConfig.pools12);
            collectRuleFixes('final', this.finalPools);
            return fixes;
        },
        stageFlowRecommendation() {
            const missingRuleItem = this.stageFlowBreakdown.find(item => item.action === 'add-rule');
            const firstError = this.stageValidationIssues.find(issue => issue.level === 'error');
            const firstWarning = this.stageValidationIssues.find(issue => issue.level === 'warning');

            if (this.autoFixableStageIssues.length > 0) {
                return {
                    type: 'apply-fixes',
                    label: this.$t('tournaments.stageValidationApplyAllFixes', { count: this.autoFixableStageIssues.length }),
                    message: this.$t('tournaments.stageFlowRecommendationFixes')
                };
            }

            if (missingRuleItem) {
                return {
                    type: 'add-rule',
                    key: missingRuleItem.key,
                    label: this.$t('tournaments.stageFlowBreakdownActionAddRule'),
                    message: this.$t('tournaments.stageFlowRecommendationMissingRule', { label: missingRuleItem.label })
                };
            }

            if (firstError) {
                return {
                    type: 'review',
                    field: firstError.fields?.[0] || null,
                    label: this.$t('tournaments.stageFlowBreakdownActionReview'),
                    message: this.$t('tournaments.stageFlowRecommendationError')
                };
            }

            if (firstWarning) {
                return {
                    type: 'review',
                    field: firstWarning.fields?.[0] || null,
                    label: this.$t('tournaments.stageFlowBreakdownActionReview'),
                    message: this.$t('tournaments.stageFlowRecommendationWarnings')
                };
            }

            return {
                type: 'save',
                label: this.$t('tournaments.saveRounds'),
                message: this.$t('tournaments.stageFlowRecommendationSave')
            };
        },
        stageFlowPreviewItems() {
            const buildPreview = (transition, label, rules, targetType, targetGroupCount) => {
                if (!Array.isArray(rules) || rules.length === 0) {
                    return {
                        key: transition,
                        label,
                        message: this.$t('tournaments.stageFlowPreviewMissing')
                    };
                }
                const fragments = rules.map(rule => {
                    const places = this.normalizeRulePlaces(rule?.fromPlacesText).unique.sort((a, b) => a - b).join(',');
                    const qualifiedCount = this.getRuleQualifiedCount(transition, rule);
                    const targetLabel = targetType === 'knockout'
                        ? this.$t('tournaments.knockoutLabel')
                        : this.$t('tournaments.targetGroupsLabel', { count: targetGroupCount || rule?.targetGroupCount || 1 });
                    const base = this.$t('tournaments.stageFlowPreviewRule', {
                        places: places || '–',
                        target: targetLabel
                    });
                    if (qualifiedCount == null) {
                        return base;
                    }
                    return this.$t('tournaments.stageFlowPreviewRuleWithCount', {
                        base,
                        count: qualifiedCount
                    });
                });
                return {
                    key: transition,
                    label,
                    message: fragments.join(' · ')
                };
            };

            const items = [];
            if (this.stageConfig.useIntermediateStage) {
                items.push(buildPreview(
                    'stage2',
                    this.$t('tournaments.promotionRule12'),
                    this.stageConfig.pools12,
                    this.stageConfig.stage2Type,
                    this.stageConfig.stage2GroupCount
                ));
                items.push(buildPreview(
                    'final',
                    this.$t('tournaments.promotionRuleFinal', { from: 2, to: 3 }),
                    this.finalPools,
                    this.stageConfig.finalStageType,
                    this.stageConfig.finalStageGroupCount
                ));
            } else {
                items.push(buildPreview(
                    'final',
                    this.$t('tournaments.promotionRuleFinal', { from: 1, to: 3 }),
                    this.finalPools,
                    this.stageConfig.finalStageType,
                    this.stageConfig.finalStageGroupCount
                ));
            }
            return items;
        },
        hasBlockingStageValidationIssues() {
            return this.stageValidationIssues.some(issue => issue.level === 'error');
        },
        stageValidationFieldMap() {
            const map = {};
            this.stageValidationIssues.forEach(issue => {
                if (!Array.isArray(issue.fields)) return;
                issue.fields.forEach(field => {
                    map[field] ||= [];
                    map[field].push(issue);
                });
            });
            return map;
        },
        stageFlowSummary() {
            if (this.stageConfig.useIntermediateStage) {
                return this.$t('tournaments.stageFlowWithIntermediate', {
                    stage2: this.stageTypeLabel(this.stageConfig.stage2Type),
                    final: this.stageTypeLabel(this.stageConfig.finalStageType)
                });
            }
            return this.$t('tournaments.stageFlowDirectFinal', {
                final: this.stageTypeLabel(this.stageConfig.finalStageType)
            });
        },
        currentPreliminaryGroupCount() {
            const currentGroups = (this.groups || []).filter(group => group && (group.stageId == null || group.stageId === 1));
            if (currentGroups.length > 0) {
                return currentGroups.length;
            }
            const fallback = Number(this.plannedGroupCount);
            return Number.isInteger(fallback) && fallback > 0 ? fallback : null;
        },
        effectiveGroups() {
            return Array.isArray(this.groups) ? this.groups : [];
        }
    },
    watch: {
        tournamentId: {
            immediate: true,
            handler() {
                this.loadStageConfig();
            }
        }
    },
    emits: [
        'update:tournamentName',
        'update:tournamentDate',
        'update:winningSets',
        'update:numberOfTables',
        'update:isGroupTournament',
        'generate-pdf',
        'edit-class',
        'save-class-edit',
        'cancel-class-edit',
        'delete-class',
        'add-class',
        'add-class-error',
        'handle-class-input-blur',
        'update:editingClassName',
        'update:editingClassIsDoubles',
        'update:editingClassGender',
        'update:editingClassMinBirthYear',
        'update:newClassName',
        'update:newClassIsDoubles',
        'update:newClassGender',
        'update:newClassMinBirthYear'
    ]
    ,
    methods: {
        stageTypeLabel(type) {
            return type === 'knockout' ? this.$t('tournaments.knockoutLabel') : this.$t('tournaments.groupsLabel');
        },
        poolRulePreview(rule, stage) {
            const places = String(rule?.fromPlacesText || '')
                .split(',')
                .map(value => value.trim())
                .filter(Boolean)
                .join(', ');
            const targetType = stage === 'final' && this.stageConfig.finalStageType === 'knockout'
                ? 'knockout'
                : (rule?.targetType || 'groups');
            const targetLabel = targetType === 'knockout'
                ? this.$t('tournaments.poolRuleTargetKnockout')
                : this.$t('tournaments.poolRuleTargetGroupsDetailed', {
                    count: rule?.targetGroupCount || (stage === 'final' ? this.stageConfig.finalStageGroupCount || 1 : this.stageConfig.stage2GroupCount || 2)
                });
            return this.$t('tournaments.poolRulePreview', {
                places: places || '–',
                target: targetLabel
            });
        },
        applyPresetRule(rule, value) {
            if (!rule) return;
            rule.fromPlacesText = value;
        },
        normalizeRulePlaces(text) {
            const rawValues = String(text || '')
                .split(',')
                .map(value => value.trim())
                .filter(Boolean);
            const parsed = rawValues.map(value => Number(value));
            return {
                rawValues,
                parsed,
                valid: parsed.every(value => Number.isInteger(value) && value > 0),
                unique: [...new Set(parsed.filter(value => Number.isInteger(value) && value > 0))]
            };
        },
        isPowerOfTwo(value) {
            const n = Number(value);
            return Number.isInteger(n) && n > 0 && (n & (n - 1)) === 0;
        },
        getSourceGroupCount(transition) {
            if (transition === 'stage2') {
                return this.currentPreliminaryGroupCount;
            }
            if (transition === 'final' && this.stageConfig.useIntermediateStage && this.stageConfig.stage2Type === 'groups') {
                const count = Number(this.stageConfig.stage2GroupCount);
                return Number.isInteger(count) && count > 0 ? count : null;
            }
            if (transition === 'final' && !this.stageConfig.useIntermediateStage) {
                return this.currentPreliminaryGroupCount;
            }
            return null;
        },
        getSourceGroupsForTransition(transition) {
            if (transition === 'stage2') {
                return this.effectiveGroups.filter(group => group && (group.stageId == null || group.stageId === undefined));
            }
            if (transition === 'final' && this.stageConfig.useIntermediateStage && this.stageConfig.stage2Type === 'groups') {
                return this.effectiveGroups.filter(group => group && Number(group.stageId) === Number(this.stageConfig.stage2StageId));
            }
            if (transition === 'final' && !this.stageConfig.useIntermediateStage) {
                return this.effectiveGroups.filter(group => group && (group.stageId == null || group.stageId === undefined));
            }
            return [];
        },
        getSourceGroupMatchesForTransition(transition) {
            const sourceGroupIds = new Set(this.getSourceGroupsForTransition(transition).map(group => Number(group.groupId ?? group.id)));
            return (Array.isArray(this.groupMatches) ? this.groupMatches : []).filter(match => sourceGroupIds.has(Number(match.groupId)));
        },
        isGroupReadyForAdvancement(group, transition = 'stage2') {
            const participants = Array.isArray(group?.participants) ? group.participants : [];
            if (participants.length < 2) {
                return true;
            }
            const groupId = Number(group?.groupId ?? group?.id);
            const matches = this.getSourceGroupMatchesForTransition(transition)
                .filter(match => Number(match.groupId) === groupId);
            const positions = participants
                .map(participant => Number(participant.position || 0))
                .filter(position => Number.isInteger(position) && position > 0);
            return matches.length > 0
                && matches.every(match => match.isFinished)
                && positions.length === participants.length
                && new Set(positions).size === positions.length;
        },
        getTransitionReadiness(transition) {
            const sourceGroups = this.getSourceGroupsForTransition(transition);
            if (sourceGroups.length === 0) {
                return {
                    ready: false,
                    message: this.$t('tournaments.stageFlowReadinessNoGroups')
                };
            }
            const incompleteGroups = sourceGroups.filter(group => !this.isGroupReadyForAdvancement(group, transition));
            if (incompleteGroups.length > 0) {
                return {
                    ready: false,
                    message: this.$t('tournaments.stageFlowReadinessIncompleteGroups', { count: incompleteGroups.length })
                };
            }
            return {
                ready: true,
                message: this.$t('tournaments.stageFlowReadinessReady')
            };
        },
        getRuleQualifiedCount(transition, rule) {
            const places = this.normalizeRulePlaces(rule?.fromPlacesText).unique;
            const sourceGroups = this.getSourceGroupsForTransition(transition);
            const allReady = sourceGroups.length > 0 && sourceGroups.every(group => this.isGroupReadyForAdvancement(group, transition));
            if (allReady && places.length > 0) {
                return sourceGroups.reduce((count, group) => {
                    const participants = Array.isArray(group?.participants) ? group.participants : [];
                    return count + participants.filter(participant => places.includes(Number(participant.position || 0))).length;
                }, 0);
            }
            const sourceGroupCount = this.getSourceGroupCount(transition);
            if (!Number.isInteger(sourceGroupCount) || sourceGroupCount < 1 || places.length < 1) {
                return null;
            }
            return sourceGroupCount * places.length;
        },
        getRuleQualifiedPreview(transition, rule) {
            const places = this.normalizeRulePlaces(rule?.fromPlacesText).unique;
            if (places.length === 0) return [];
            const sourceGroups = this.getSourceGroupsForTransition(transition);
            const allReady = sourceGroups.length > 0 && sourceGroups.every(group => this.isGroupReadyForAdvancement(group, transition));
            if (!allReady) return [];

            return sourceGroups.flatMap((group, groupIndex) => {
                const participants = Array.isArray(group?.participants) ? group.participants : [];
                return participants
                    .filter(participant => places.includes(Number(participant.position || 0)))
                    .map(participant => ({
                        key: `${group.groupId ?? group.id}-${participant.id}-${participant.position}`,
                        label: this.$t('tournaments.stageFlowQualifiedPreviewEntry', {
                            group: group.groupNumber || groupIndex + 1,
                            position: participant.position,
                            name: participant.name
                        })
                    }));
            });
        },
        validatePoolRules(rules, options = {}) {
            const stageLabel = options.stageLabel || this.$t('tournaments.finalRound');
            const transition = options.transition || 'stage';
            const forceKnockout = options.forceKnockout === true;
            const allowGroupsTarget = options.allowGroupsTarget !== false;
            const expectedTargetType = options.expectedTargetType || null;
            const expectedGroupCount = Number(options.expectedGroupCount || 0);
            const sourceGroupCount = this.getSourceGroupCount(transition);
            const issues = [];
            const placeMap = new Map();

            if (!Array.isArray(rules) || rules.length === 0) {
                issues.push({
                    code: 'no-rules',
                    transition,
                    level: 'warning',
                    title: stageLabel,
                    message: this.$t('tournaments.stageValidationNoRules', { stage: stageLabel }),
                    fields: []
                });
                return issues;
            }

            rules.forEach((rule, index) => {
                const ruleLabel = this.$t('tournaments.poolRuleLabel', { number: index + 1 });
                const normalized = this.normalizeRulePlaces(rule?.fromPlacesText);
                const targetType = forceKnockout ? 'knockout' : (rule?.targetType || 'groups');

                if (normalized.rawValues.length === 0) {
                    issues.push({
                        code: 'missing-places',
                        transition,
                        level: 'error',
                        title: `${stageLabel}: ${ruleLabel}`,
                        message: this.$t('tournaments.stageValidationRulePlacesRequired'),
                        fields: [`${transition}:${index}:places`]
                    });
                    return;
                }

                if (!normalized.valid) {
                    issues.push({
                        code: 'invalid-places',
                        transition,
                        level: 'error',
                        title: `${stageLabel}: ${ruleLabel}`,
                        message: this.$t('tournaments.stageValidationRulePlacesInvalid'),
                        fields: [`${transition}:${index}:places`]
                    });
                    return;
                }

                if (normalized.unique.length !== normalized.parsed.length) {
                    issues.push({
                        code: 'duplicate-places',
                        transition,
                        level: 'error',
                        title: `${stageLabel}: ${ruleLabel}`,
                        message: this.$t('tournaments.stageValidationRulePlacesDuplicate'),
                        fields: [`${transition}:${index}:places`]
                    });
                }

                if (
                    normalized.unique.length > 1 &&
                    normalized.unique.some((place, placeIndex) => placeIndex > 0 && place !== normalized.unique[placeIndex - 1] + 1)
                ) {
                    issues.push({
                        code: 'non-contiguous-places',
                        transition,
                        level: 'warning',
                        title: `${stageLabel}: ${ruleLabel}`,
                        message: this.$t('tournaments.stageValidationRulePlacesGap'),
                        fields: [`${transition}:${index}:places`]
                    });
                }

                normalized.unique.forEach(place => {
                    const existingRule = placeMap.get(place);
                    if (existingRule != null) {
                        issues.push({
                            code: `overlap-${place}`,
                            transition,
                            level: 'error',
                            title: stageLabel,
                            message: this.$t('tournaments.stageValidationRulesOverlap', {
                                place,
                                first: existingRule,
                                second: index + 1
                            }),
                            fields: [`${transition}:${existingRule - 1}:places`, `${transition}:${index}:places`]
                        });
                    } else {
                        placeMap.set(place, index + 1);
                    }
                });

                if (!forceKnockout && targetType === 'groups') {
                    const groupCount = Number(rule?.targetGroupCount);
                    if (!Number.isInteger(groupCount) || groupCount < 1) {
                        issues.push({
                            code: 'target-groups-required',
                            transition,
                            level: 'error',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationTargetGroupsRequired'),
                            fields: [`${transition}:${index}:targetGroupCount`]
                        });
                    } else if (expectedTargetType === 'groups' && Number.isInteger(expectedGroupCount) && expectedGroupCount > 0 && groupCount !== expectedGroupCount) {
                        issues.push({
                            code: 'target-groups-mismatch',
                            transition,
                            level: 'error',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationTargetGroupCountMismatch', {
                                expected: expectedGroupCount
                            }),
                            fields: [`${transition}:${index}:targetGroupCount`]
                        });
                    }
                }

                if (!allowGroupsTarget && targetType === 'groups') {
                    issues.push({
                        code: 'target-mismatch',
                            transition,
                            level: 'error',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationKnockoutTargetOnly'),
                        fields: [`${transition}:${index}:targetType`]
                    });
                } else if (expectedTargetType && targetType !== expectedTargetType) {
                    issues.push({
                        code: 'target-type-mismatch',
                        transition,
                        level: 'error',
                        title: `${stageLabel}: ${ruleLabel}`,
                        message: this.$t('tournaments.stageValidationTargetTypeMismatch', {
                            target: expectedTargetType === 'knockout'
                                ? this.$t('tournaments.knockoutLabel')
                                : this.$t('tournaments.groupsLabel')
                        }),
                        fields: [`${transition}:${index}:targetType`]
                    });
                }

                const qualifiedCount = this.getRuleQualifiedCount(transition, rule);
                if (qualifiedCount != null && targetType === 'knockout') {
                    if (qualifiedCount < 2) {
                        issues.push({
                            code: 'knockout-too-small',
                            transition,
                            level: 'error',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationKnockoutNeedsTwoPlayers'),
                            fields: [`${transition}:${index}:places`, `${transition}:${index}:targetType`]
                        });
                    } else if (!this.isPowerOfTwo(qualifiedCount)) {
                        issues.push({
                            code: 'knockout-byes-likely',
                            transition,
                            level: 'warning',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationKnockoutByesLikely', { count: qualifiedCount }),
                            fields: [`${transition}:${index}:places`]
                        });
                    }
                }

                if (qualifiedCount != null && targetType === 'groups' && Number.isInteger(expectedGroupCount) && expectedGroupCount > 0) {
                    if (qualifiedCount < expectedGroupCount) {
                        issues.push({
                            code: 'groups-too-few-qualifiers',
                            transition,
                            level: 'error',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationNotEnoughQualifiersForGroups', { count: qualifiedCount, groups: expectedGroupCount }),
                            fields: [`${transition}:${index}:places`, `${transition}:${index}:targetGroupCount`]
                        });
                    } else if (qualifiedCount < expectedGroupCount * 2) {
                        issues.push({
                            code: 'groups-thin',
                            transition,
                            level: 'warning',
                            title: `${stageLabel}: ${ruleLabel}`,
                            message: this.$t('tournaments.stageValidationThinGroupsLikely', { count: qualifiedCount, groups: expectedGroupCount }),
                            fields: [`${transition}:${index}:places`, `${transition}:${index}:targetGroupCount`]
                        });
                    }
                }
            });

            return issues;
        },
        hasStageFieldError(fieldKey) {
            return (this.stageValidationFieldMap[fieldKey] || []).some(issue => issue.level === 'error');
        },
        hasRuleFieldError(transition, index, field) {
            return (this.stageValidationFieldMap[`${transition}:${index}:${field}`] || []).some(issue => issue.level === 'error');
        },
        getStageFieldHint(fieldKey) {
            return (this.stageValidationFieldMap[fieldKey] || [])[0]?.message || '';
        },
        getRuleFieldHint(transition, index, field) {
            return (this.stageValidationFieldMap[`${transition}:${index}:${field}`] || [])[0]?.message || '';
        },
        getNormalizedPlacesSuggestion(text) {
            const normalized = this.normalizeRulePlaces(text);
            if (normalized.unique.length === 0) return '';
            const suggestion = normalized.unique.sort((a, b) => a - b).join(',');
            const raw = String(text || '').replace(/\s+/g, '');
            if (!suggestion || suggestion === raw) return '';
            return suggestion;
        },
        getRulePlacesSuggestion(transition, index) {
            if (!this.hasRuleFieldError(transition, index, 'places')) return '';
            const rules = transition === 'final' ? this.finalPools : this.stageConfig.pools12;
            const rule = rules[index];
            return this.getNormalizedPlacesSuggestion(rule?.fromPlacesText);
        },
        getExpectedTargetType(transition) {
            return transition === 'final'
                ? this.stageConfig.finalStageType
                : this.stageConfig.stage2Type;
        },
        getExpectedTargetGroupCount(transition) {
            return transition === 'final'
                ? Number(this.stageConfig.finalStageGroupCount || 0)
                : Number(this.stageConfig.stage2GroupCount || 0);
        },
        getRuleFieldIssues(transition, index, field) {
            return this.stageValidationFieldMap[`${transition}:${index}:${field}`] || [];
        },
        getRuleIssues(transition, index) {
            return this.stageValidationIssues.filter(issue =>
                Array.isArray(issue.fields) &&
                issue.fields.some(field => field.startsWith(`${transition}:${index}:`))
            );
        },
        getRuleStatus(transition, index) {
            const issues = this.getRuleIssues(transition, index);
            if (issues.some(issue => issue.level === 'error')) {
                return { level: 'error', issue: issues.find(issue => issue.level === 'error') };
            }
            if (issues.some(issue => issue.level === 'warning')) {
                return { level: 'warning', issue: issues.find(issue => issue.level === 'warning') };
            }
            return { level: 'ok', issue: null };
        },
        getRuleStatusLabel(transition, index) {
            const status = this.getRuleStatus(transition, index);
            if (status.level === 'error') return this.$t('tournaments.ruleStatusBlocked');
            if (status.level === 'warning') return this.$t('tournaments.ruleStatusReview');
            return this.$t('tournaments.ruleStatusOk');
        },
        getRuleStatusMessage(transition, index) {
            const status = this.getRuleStatus(transition, index);
            if (status.issue?.message) return status.issue.message;
            return this.$t('tournaments.ruleStatusOkDescription');
        },
        hasRuleQuickFix(transition, index, field) {
            return this.getRuleQuickFixLabel(transition, index, field) !== '';
        },
        getRuleQuickFixLabel(transition, index, field) {
            const issues = this.getRuleFieldIssues(transition, index, field);
            if (field === 'targetType' && issues.some(issue => issue.code === 'target-type-mismatch' || issue.code === 'target-mismatch')) {
                return this.$t('tournaments.stageValidationApplyTargetTypeFix', {
                    target: this.getExpectedTargetType(transition) === 'knockout'
                        ? this.$t('tournaments.knockoutLabel')
                        : this.$t('tournaments.groupsLabel')
                });
            }
            if (field === 'targetGroupCount' && issues.some(issue => issue.code === 'target-groups-required' || issue.code === 'target-groups-mismatch')) {
                return this.$t('tournaments.stageValidationApplyTargetGroupFix', {
                    count: this.getExpectedTargetGroupCount(transition)
                });
            }
            return '';
        },
        applyRulePlacesSuggestion(transition, index) {
            const rules = transition === 'final' ? this.finalPools : this.stageConfig.pools12;
            const suggestion = this.getRulePlacesSuggestion(transition, index);
            if (!suggestion || !rules[index]) return;
            rules[index].fromPlacesText = suggestion;
        },
        applyRuleQuickFix(transition, index, field) {
            const rules = transition === 'final' ? this.finalPools : this.stageConfig.pools12;
            const rule = rules[index];
            if (!rule) return;
            if (field === 'targetType') {
                rule.targetType = this.getExpectedTargetType(transition);
                if (rule.targetType === 'groups' && (!Number.isInteger(Number(rule.targetGroupCount)) || Number(rule.targetGroupCount) < 1)) {
                    rule.targetGroupCount = Math.max(1, this.getExpectedTargetGroupCount(transition) || 1);
                }
                return;
            }
            if (field === 'targetGroupCount') {
                rule.targetGroupCount = Math.max(1, this.getExpectedTargetGroupCount(transition) || 1);
            }
        },
        focusStageField(fieldKey) {
            if (!fieldKey) return;
            this.$nextTick(() => {
                const element = this.$el?.querySelector?.(`[data-field-key="${fieldKey}"]`);
                if (!element) return;
                const ruleKey = fieldKey.includes(':')
                    ? fieldKey.split(':').slice(0, 2).join(':')
                    : null;
                this.highlightRule(ruleKey);
                element.scrollIntoView({ behavior: 'smooth', block: 'center' });
                if (typeof element.focus === 'function') {
                    element.focus();
                }
            });
        },
        handleStageFlowBreakdownClick(item) {
            if (!item) return;
            if (item.action === 'add-rule') {
                this.addPoolRule(item.key === 'stage2' ? '12' : 'final');
                this.$nextTick(() => {
                    const rules = item.key === 'stage2' ? this.stageConfig.pools12 : this.finalPools;
                    const index = Math.max(0, rules.length - 1);
                    this.focusStageField(`${item.key}:${index}:places`);
                });
                return;
            }
            this.focusStageField(item.focusField);
        },
        applyAllStageQuickFixes() {
            this.autoFixableStageIssues.forEach(fix => {
                if (fix.type === 'places') {
                    this.applyRulePlacesSuggestion(fix.transition, fix.index);
                    return;
                }
                this.applyRuleQuickFix(fix.transition, fix.index, fix.type);
            });
            const firstFix = this.autoFixableStageIssues[0];
            if (firstFix) {
                const field = firstFix.type === 'places' ? 'places' : firstFix.type;
                this.focusStageField(`${firstFix.transition}:${firstFix.index}:${field}`);
            }
        },
        runStageFlowRecommendation() {
            const recommendation = this.stageFlowRecommendation;
            if (!recommendation) return;
            if (recommendation.type === 'apply-fixes') {
                this.applyAllStageQuickFixes();
                return;
            }
            if (recommendation.type === 'add-rule') {
                this.handleStageFlowBreakdownClick({
                    key: recommendation.key,
                    action: 'add-rule'
                });
                return;
            }
            if (recommendation.type === 'review') {
                this.focusStageField(recommendation.field);
                return;
            }
            if (recommendation.type === 'save') {
                this.onSaveClick();
            }
        },
        highlightRule(ruleKey) {
            if (!ruleKey) return;
            if (this.highlightedRuleTimer) {
                clearTimeout(this.highlightedRuleTimer);
                this.highlightedRuleTimer = null;
            }
            if (this.highlightedRuleElement) {
                this.highlightedRuleElement.classList.remove('pool-rule--highlighted');
            }
            const ruleElement = this.$el?.querySelector?.(`[data-rule-key="${ruleKey}"]`);
            if (!ruleElement) return;
            ruleElement.classList.add('pool-rule--highlighted');
            this.highlightedRuleElement = ruleElement;
            this.highlightedRuleTimer = setTimeout(() => {
                if (this.highlightedRuleElement) {
                    this.highlightedRuleElement.classList.remove('pool-rule--highlighted');
                    this.highlightedRuleElement = null;
                }
                this.highlightedRuleTimer = null;
            }, 2200);
        },
        onSaveClick() {
            if (this.hasBlockingStageValidationIssues) {
                const firstIssue = this.stageValidationIssues.find(issue => issue.level === 'error');
                this.stageConfig.error = firstIssue?.message || this.$t('tournaments.stageValidationSaveBlocked');
                this.stageConfig.success = null;
                return;
            }
            this.saveStageConfig();
        },

        async onThirdPlaceToggle(checked) {
            // UI sofort aktualisieren
            this.stageConfig.finalStageThirdPlace = checked === true;
            this.stageConfig.error = null;
            this.stageConfig.success = null;

            if (!this.clubId || !this.tournamentId) {
                this.stageConfig.error = this.$t('tournaments.stageConfigMissingIds');
                return;
            }

            // Unabhängig von Pool-Regeln speichern:
            // wir laden die aktuelle Stage-Konfiguration und patchen nur target.thirdPlace.
            try {
                const getRes = await apiClient.get('/tournament/stages', {
                    params: {
                        clubId: Number(this.clubId),
                        tournamentId: Number(this.tournamentId),
                    }
                });
                if (getRes.status >= 400) throw new Error(getRes.data?.error || this.$t('tournaments.stageConfigLoadError'));

                if (!Array.isArray(getRes.data?.stages) || !Array.isArray(getRes.data?.advancements)) {
                    throw new Error(this.$t('tournaments.stageConfigBadServerResponse'));
                }

                let stages = Array.isArray(getRes.data?.stages) ? getRes.data.stages : [];
                let advancements = Array.isArray(getRes.data?.advancements) ? getRes.data.advancements : [];

                // Wenn noch keine Konfiguration existiert, können wir das Flag nicht "isoliert" speichern.
                // Dann erzeugen wir eine minimale Stage+Advancement-Konfiguration (mit Default-Poolregel),
                // damit thirdPlace überhaupt persistiert werden kann.
                if (stages.length === 0 && advancements.length === 0) {
                    const built = this.buildPayload();
                    stages = built.stages;
                    advancements = built.advancements;

                    // Falls der Nutzer noch keine Pool-Regeln angelegt hat, legen wir eine Default-Regel an,
                    // damit der Backend-Validator nicht abbricht.
                    for (const adv of advancements) {
                        const pools = adv?.config?.pools;
                        if (!Array.isArray(pools) || pools.length === 0) {
                            adv.config = adv.config || {};
                            adv.config.pools = [{
                                fromPlaces: [1, 2],
                                target: { type: 'knockout', singleField: true, thirdPlace: checked === true },
                            }];
                        }
                    }
                }

                const patchedAdvancements = advancements.map(a => {
                    // Wenn wir gerade initial erzeugen (adv hat fromStageIndex/toStageIndex), patchen wir direkt.
                    if (a && a.fromStageIndex != null && a.toStageIndex != null) {
                        const isFinal = (Number(a.fromStageIndex) === 1 && Number(a.toStageIndex) === 3)
                            || (Number(a.fromStageIndex) === 2 && Number(a.toStageIndex) === 3);
                        if (!isFinal) return a;
                        const cfg = a?.config && typeof a.config === 'object' ? a.config : {};
                        const pools = Array.isArray(cfg.pools) ? cfg.pools : [];
                        return {
                            ...a,
                            config: {
                                ...cfg,
                                pools: pools.map(p => {
                                    const target = p?.target && typeof p.target === 'object' ? p.target : {};
                                    if (target.type === 'knockout') {
                                        return { ...p, target: { ...target, thirdPlace: checked === true } };
                                    }
                                    return p;
                                })
                            }
                        };
                    }

                    // Existing DB-shape: patch nur Final-Übergang (1->3 / 2->3) via stageId mapping
                    // Nur Final-Übergang patchen: (1->3) oder (2->3)
                    const stageById = new Map(stages.map(s => [Number(s.id), s]));
                    const fromIdx = Number(stageById.get(Number(a?.fromStageId))?.index);
                    const toIdx = Number(stageById.get(Number(a?.toStageId))?.index);
                    const isFinal = (fromIdx === 1 && toIdx === 3) || (fromIdx === 2 && toIdx === 3);
                    if (!isFinal) return a;

                    const cfg = a?.config && typeof a.config === 'object' ? a.config : {};
                    const pools = Array.isArray(cfg.pools) ? cfg.pools : [];
                    return {
                        ...a,
                        config: {
                            ...cfg,
                            pools: pools.map(p => {
                                const target = p?.target && typeof p.target === 'object' ? p.target : {};
                                if (target.type === 'knockout') {
                                    return { ...p, target: { ...target, thirdPlace: checked === true } };
                                }
                                return p;
                            })
                        }
                    };
                });

                const putRes = await apiClient.put('/tournament/stages', {
                    clubId: Number(this.clubId),
                    tournamentId: Number(this.tournamentId),
                    stages,
                    advancements: patchedAdvancements,
                });
                if (putRes.status >= 400) throw new Error(putRes.data?.error || 'Fehler beim Speichern');

                await this.loadStageConfig();
                this.stageConfig.success = this.$t('common.saved');
            } catch (e) {
                this.stageConfig.error = e?.message || String(e);
            }
        },
        async loadStageConfig() {
            if (!this.clubId || !this.tournamentId) return;
            this.stageConfig.loading = true;
            this.stageConfig.error = null;
            this.stageConfig.success = null;

            try {
                const res = await apiClient.get('/tournament/stages', {
                    params: {
                        clubId: Number(this.clubId),
                        tournamentId: Number(this.tournamentId),
                    }
                });
                if (res.status >= 400) throw new Error(res.data?.error || this.$t('tournaments.stageConfigLoadError'));

                const stages = Array.isArray(res.data?.stages) ? res.data.stages : [];
                const advancements = Array.isArray(res.data?.advancements) ? res.data.advancements : [];

                // Zwischenrunde optional: wenn Stage 2 fehlt, gehen wir von direkter Endrunde aus.
                const stage2 = stages.find(s => Number(s.index) === 2);
                this.stageConfig.useIntermediateStage = !!stage2;

                if (stage2) {
                    this.stageConfig.stage2StageId = Number(stage2.id);
                    this.stageConfig.stage2Type = stage2.type || 'groups';
                    this.stageConfig.stage2GroupCount = stage2.numberOfGroups || 2;
                } else {
                    this.stageConfig.stage2StageId = null;
                }

                const stage3 = stages.find(s => Number(s.index) === 3);
                if (stage3) {
                    this.stageConfig.finalStageId = Number(stage3.id);
                    this.stageConfig.finalStageType = stage3.type || 'knockout';
                    this.stageConfig.finalStageGroupCount = stage3.numberOfGroups || 1;
                } else {
                    // Fallback, wenn bisher nur 1->2 existierte
                    this.stageConfig.finalStageId = null;
                    this.stageConfig.finalStageType = 'knockout';
                    this.stageConfig.finalStageGroupCount = 1;
                }

                const adv12 = advancements.find(a => Number(a?.fromStageId) && Number(a?.toStageId) && Number(stages.find(s => s.id === a.fromStageId)?.index) === 1 && Number(stages.find(s => s.id === a.toStageId)?.index) === 2) || null;
                const advFinal = advancements.find(a => {
                    const fromIdx = Number(stages.find(s => s.id === a.fromStageId)?.index);
                    const toIdx = Number(stages.find(s => s.id === a.toStageId)?.index);
                    return (fromIdx === 1 && toIdx === 3) || (fromIdx === 2 && toIdx === 3);
                }) || null;

                const pools12 = Array.isArray(adv12?.config?.pools) ? adv12.config.pools : [];
                this.stageConfig.pools12 = pools12.map(p => ({
                    fromPlacesText: Array.isArray(p.fromPlaces) ? p.fromPlaces.join(',') : '',
                    targetType: p?.target?.type || 'groups',
                    targetGroupCount: p?.target?.groupCount || this.stageConfig.stage2GroupCount || 2,
                }));

                const poolsFinal = Array.isArray(advFinal?.config?.pools) ? advFinal.config.pools : [];
                this.stageConfig.poolsFinal = poolsFinal.map(p => ({
                    fromPlacesText: Array.isArray(p.fromPlaces) ? p.fromPlaces.join(',') : '',
                    // final-stage Modus ist führend: wenn KO gewählt, setzen wir Ziel automatisch auf KO
                    targetType: (this.stageConfig.finalStageType === 'knockout') ? 'knockout' : (p?.target?.type || 'groups'),
                    targetGroupCount: p?.target?.groupCount || this.stageConfig.finalStageGroupCount || 1,
                }));

                // KO-Flag gilt für die gesamte Endrunde: true, sobald irgendeine Final-KO-Regel thirdPlace=true hat.
                this.stageConfig.finalStageThirdPlace = poolsFinal.some(p => p?.target?.type === 'knockout' && p?.target?.thirdPlace === true);
            } catch (e) {
                this.stageConfig.error = e?.message || String(e);
            } finally {
                this.stageConfig.loading = false;
            }
        },
        addPoolRule(which = '12') {
            const isFinal = which === 'final';
            const targetArray = isFinal ? this.stageConfig.poolsFinal : this.stageConfig.pools12;
            targetArray.push({
                fromPlacesText: '1,2',
                targetType: isFinal
                    ? (this.stageConfig.finalStageType === 'knockout' ? 'knockout' : 'groups')
                    : 'groups',
                targetGroupCount: isFinal
                    ? (this.stageConfig.finalStageGroupCount || 1)
                    : (this.stageConfig.stage2GroupCount || 2),
            });
        },
        removePoolRule(idx, which = '12') {
            const targetArray = (which === 'final') ? this.stageConfig.poolsFinal : this.stageConfig.pools12;
            targetArray.splice(idx, 1);
        },
    buildPoolsPayload(rules, defaultGroupCount, knockoutSingleField = false, knockoutThirdPlace = false) {
            return (rules || [])
                .map(r => {
                    const fromPlaces = String(r.fromPlacesText || '')
                        .split(',')
                        .map(x => Number(String(x).trim()))
                        .filter(n => Number.isFinite(n) && n > 0);
                    // Wenn Endrunde KO ist, erzwingen wir KO als Ziel, damit man KO nicht doppelt einstellen muss.
                    const forceKnockout = this.stageConfig.finalStageType === 'knockout';
                    return {
                        fromPlaces,
                        target: (forceKnockout || r.targetType === 'knockout')
                            ? { type: 'knockout', singleField: knockoutSingleField, thirdPlace: knockoutThirdPlace }
                            : { type: 'groups', groupCount: Math.max(1, Number(r.targetGroupCount || defaultGroupCount || 1)) }
                    };
                })
                .filter(p => p.fromPlaces.length > 0);
        },
        buildPayload() {
            const pools12 = this.stageConfig.useIntermediateStage
                ? this.buildPoolsPayload(this.stageConfig.pools12, this.stageConfig.stage2GroupCount || 2, false)
                : [];
            const poolsFinal = this.buildPoolsPayload(
                this.stageConfig.poolsFinal,
                this.stageConfig.finalStageGroupCount || 1,
                true,
                this.stageConfig.finalStageThirdPlace === true
            );

            const stages = [
                { index: 1, type: 'groups', name: 'Vorrunde' },
            ];
            const advancements = [];

            if (this.stageConfig.useIntermediateStage) {
                stages.push({
                    index: 2,
                    type: this.stageConfig.stage2Type,
                    name: 'Zwischenrunde',
                    numberOfGroups: this.stageConfig.stage2Type === 'groups'
                        ? Math.max(1, Number(this.stageConfig.stage2GroupCount || 1))
                        : null,
                });

                advancements.push({
                    fromStageIndex: 1,
                    toStageIndex: 2,
                    mode: 'pools',
                    config: { pools: pools12 },
                });

                stages.push({
                    index: 3,
                    type: this.stageConfig.finalStageType,
                    name: 'Endrunde',
                    numberOfGroups: this.stageConfig.finalStageType === 'groups'
                        ? Math.max(1, Number(this.stageConfig.finalStageGroupCount || 1))
                        : null,
                });

                advancements.push({
                    fromStageIndex: 2,
                    toStageIndex: 3,
                    mode: 'pools',
                    config: { pools: poolsFinal },
                });
            } else {
                stages.push({
                    index: 3,
                    type: this.stageConfig.finalStageType,
                    name: 'Endrunde',
                    numberOfGroups: this.stageConfig.finalStageType === 'groups'
                        ? Math.max(1, Number(this.stageConfig.finalStageGroupCount || 1))
                        : null,
                });

                advancements.push({
                    fromStageIndex: 1,
                    toStageIndex: 3,
                    mode: 'pools',
                    config: { pools: poolsFinal },
                });
            }

            return { stages, advancements };
        },
        async saveStageConfig() {
            this.stageConfig.error = null;
            this.stageConfig.success = null;
            try {
                const { stages, advancements } = this.buildPayload();

                // Validierung: Für jeden Übergang müssen Pools vorhanden sein
                for (const adv of advancements) {
                    const hasPools = Array.isArray(adv?.config?.pools) && adv.config.pools.length > 0;
                    if (!hasPools) {
                        const label = `${adv.fromStageIndex}→${adv.toStageIndex}`;
                        throw new Error(this.$t('tournaments.atLeastOnePoolRule', { label }));
                    }
                }

                const res = await apiClient.put('/tournament/stages', {
                    clubId: Number(this.clubId),
                    tournamentId: Number(this.tournamentId),
                    stages,
                    advancements,
                });
                if (res.status >= 400) throw new Error(res.data?.error || this.$t('messages.saveFailed'));

                await this.loadStageConfig();
                this.stageConfig.success = this.$t('common.saved');
            } catch (e) {
                this.stageConfig.error = e?.message || String(e);
            }
        },
        async advanceStage(fromStageIndex, toStageIndex) {
            this.stageConfig.error = null;
            this.stageConfig.success = null;
            try {
                // Lade aktuelle Stages, um passende IDs zu ermitteln
                const getRes = await apiClient.get('/tournament/stages', {
                    params: {
                        clubId: Number(this.clubId),
                        tournamentId: Number(this.tournamentId)
                    }
                });
                const stages = Array.isArray(getRes?.data?.stages) ? getRes.data.stages : [];
                const normalized = stages.map(s => ({
                    stageIndex: Number(s.stageIndex ?? s.index ?? s.id),
                    stageId: Number(s.id ?? s.stageId ?? s.stageIndex),
                    type: s.type || s.targetType || s.target
                }));
                const from = normalized.find(s => s.stageIndex === Number(fromStageIndex));
                const to = normalized.find(s => s.stageIndex === Number(toStageIndex));

                const payload = {
                    clubId: Number(this.clubId),
                    tournamentId: Number(this.tournamentId)
                };
                if (from?.stageId && to?.stageId) {
                    payload.fromStageId = from.stageId;
                    payload.toStageId = to.stageId;
                } else {
                    payload.fromStageIndex = Number(fromStageIndex);
                    payload.toStageIndex = Number(toStageIndex);
                }

                const res = await apiClient.post('/tournament/stages/advance', payload);
                if (res.status >= 400) throw new Error(res.data?.error || this.$t('tournaments.errorCreatingGroups'));
                this.stageConfig.success = this.$t('tournaments.stageParticipantsTransferred', {
                    round: this.$t(toStageIndex === 2 ? 'tournaments.intermediateRound' : 'tournaments.finalRound')
                });
            } catch (e) {
                this.stageConfig.error = e?.message || String(e);
            }
        }
    },
    beforeUnmount() {
        if (this.highlightedRuleTimer) {
            clearTimeout(this.highlightedRuleTimer);
        }
    }
};
</script>

<style scoped>
.config-grid {
    display: grid;
    grid-template-columns: minmax(320px, 1fr) minmax(320px, 1.15fr);
    gap: 1rem;
}

.config-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 14px;
    padding: 1rem;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
}

.config-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.config-card-header h4 {
    margin: 0;
    color: #1f2937;
}

.config-summary-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.config-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    background: #f3f4f6;
    color: #4b5563;
    font-size: 0.85rem;
    font-weight: 700;
}

.tournament-info {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.9rem;
}

.tournament-info label {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    color: #374151;
    font-weight: 500;
}

.tournament-info input[type="text"],
.tournament-info input[type="date"],
.tournament-info input[type="number"] {
    padding: 0.55rem 0.7rem;
    border: 1px solid #d1d5db;
    border-radius: 10px;
    font-size: 0.95rem;
}

.config-actions {
    margin-top: 1rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.checkbox-item {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
}

.stage-config {
    border: 1px solid #e5e7eb;
    border-radius: 14px;
    background: #fff;
    padding: 1rem;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
}

.stage-config-summary {
    cursor: pointer;
    font-weight: 700;
    color: #1f2937;
}

.stage-config-intro {
    margin: 0.25rem 0 1rem;
    opacity: 0.8;
}

.stage-config-summary-box {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.8rem 0.95rem;
    margin-bottom: 1rem;
    border-radius: 12px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    color: #374151;
}

.stage-validation-list {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    margin-bottom: 1rem;
    padding: 0.9rem 1rem;
    border-radius: 12px;
    border: 1px solid #e5e7eb;
    background: #f9fafb;
}

.stage-flow-health {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin-bottom: 1rem;
    padding: 0.85rem 1rem;
    border-radius: 12px;
    border: 1px solid #e5e7eb;
}

.stage-flow-health strong {
    font-size: 0.9rem;
}

.stage-flow-health span {
    font-size: 0.92rem;
    color: #4b5563;
}

.stage-flow-health-action {
    align-self: flex-start;
    margin-top: 0.25rem;
    padding: 0.35rem 0.8rem;
    border: 1px solid #bfdbfe;
    border-radius: 999px;
    background: #eff6ff;
    color: #1d4ed8;
    font-size: 0.84rem;
    font-weight: 700;
    cursor: pointer;
}

.stage-flow-health-action:hover {
    background: #dbeafe;
}

.stage-flow-health--ok {
    background: #f0fdf4;
    border-color: #bbf7d0;
}

.stage-flow-health--ok strong {
    color: #166534;
}

.stage-flow-health--warning {
    background: #fffbeb;
    border-color: #fde68a;
}

.stage-flow-health--warning strong {
    color: #92400e;
}

.stage-flow-health--error {
    background: #fef2f2;
    border-color: #fecaca;
}

.stage-flow-health--error strong {
    color: #b91c1c;
}

.stage-flow-breakdown {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.stage-flow-preview-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-bottom: 1rem;
}

.stage-flow-preview-item {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.8rem 0.95rem;
    border-radius: 12px;
    border: 1px solid #e5e7eb;
    background: #f9fafb;
}

.stage-flow-preview-item strong {
    color: #111827;
    font-size: 0.88rem;
}

.stage-flow-preview-item span {
    color: #4b5563;
    font-size: 0.92rem;
}

.stage-flow-recommendation {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
    padding: 0.9rem 1rem;
    border-radius: 12px;
    border: 1px solid #dbeafe;
    background: #eff6ff;
}

.stage-flow-recommendation-copy {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.stage-flow-recommendation-copy strong {
    color: #1e3a8a;
}

.stage-flow-recommendation-copy span {
    color: #334155;
    font-size: 0.92rem;
}

.stage-flow-breakdown-item {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.85rem 0.95rem;
    border-radius: 12px;
    border: 1px solid #e5e7eb;
    background: #fff;
    text-align: left;
    cursor: pointer;
}

.stage-flow-breakdown-item strong {
    color: #111827;
    font-size: 0.88rem;
}

.stage-flow-breakdown-item span {
    color: #4b5563;
    font-size: 0.9rem;
}

.stage-flow-breakdown-action {
    margin-top: 0.15rem;
    color: #1d4ed8;
    font-size: 0.82rem;
    font-style: normal;
    font-weight: 700;
}

.stage-flow-breakdown-item:hover {
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
}

.stage-flow-breakdown-item--ok {
    border-color: #bbf7d0;
    background: #f0fdf4;
}

.stage-flow-breakdown-item--warning {
    border-color: #fde68a;
    background: #fffbeb;
}

.stage-flow-breakdown-item--error {
    border-color: #fecaca;
    background: #fef2f2;
}

.stage-validation-header {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.stage-validation-header strong {
    color: #111827;
}

.stage-validation-header span {
    color: #6b7280;
    font-size: 0.92rem;
}

.stage-validation-item {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.75rem 0.85rem;
    border-radius: 10px;
    border: 1px solid #e5e7eb;
    background: #fff;
}

.stage-validation-item[role="button"] {
    cursor: pointer;
}

.stage-validation-item[role="button"]:hover {
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
}

.stage-validation-item[role="button"]:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}

.stage-validation-item strong {
    color: #111827;
}

.stage-validation-item span {
    color: #4b5563;
    font-size: 0.92rem;
}

.stage-validation-item--error {
    border-color: #fecaca;
    background: #fef2f2;
}

.stage-validation-item--warning {
    border-color: #fde68a;
    background: #fffbeb;
}

.stage-config-layout {
    display: grid;
    gap: 0.9rem;
    max-width: 820px;
}

.stage-card {
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 0.9rem;
    background: #fcfcfd;
}

.stage-card-step {
    margin-bottom: 0.45rem;
    font-size: 0.8rem;
    font-weight: 700;
    color: #2563eb;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.stage-card-copy {
    margin: 0.35rem 0 0.85rem;
    color: #6b7280;
    font-size: 0.92rem;
}

.stage-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.75rem;
}

.stage-field-grid label,
.pool-rule label {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.field-invalid-label {
    color: #b91c1c;
}

.field-invalid {
    border-color: #ef4444 !important;
    background: #fef2f2;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.12);
}

.field-inline-hint {
    margin-top: 0.15rem;
    font-size: 0.82rem;
    line-height: 1.35;
}

.field-inline-hint--error {
    color: #b91c1c;
}

.field-inline-hint--hint {
    color: #1d4ed8;
}

.field-fix-button {
    align-self: flex-start;
    margin-top: 0.25rem;
    padding: 0.25rem 0.65rem;
    border: 1px solid #bfdbfe;
    border-radius: 999px;
    background: #eff6ff;
    color: #1d4ed8;
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
}

.field-fix-button:hover {
    background: #dbeafe;
}

.stage-third-place {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.pool-config {
    margin-top: 0.85rem;
    border: 1px solid #ddd;
    border-radius: 10px;
    padding: 0.85rem;
    background: #fff;
}

.pool-config-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.pool-config-copy {
    margin-top: 0.2rem;
    font-size: 0.88rem;
    color: #6b7280;
}

.pool-config-empty {
    margin-top: 0.5rem;
    opacity: 0.8;
}

.pool-rule {
    display: grid;
    gap: 0.5rem;
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid #eee;
    transition: box-shadow 0.2s ease, background-color 0.2s ease, border-radius 0.2s ease;
}

.pool-rule--highlighted {
    padding: 0.75rem;
    margin: 0.65rem -0.25rem 0;
    border-radius: 12px;
    background: #eff6ff;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.18);
    border-top-color: transparent;
}

.pool-rule-heading {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.pool-rule-summary {
    color: #6b7280;
    font-size: 0.88rem;
}

.pool-rule-preview {
    color: #374151;
    font-size: 0.88rem;
}

.pool-rule-status {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-top: 0.35rem;
    padding: 0.55rem 0.65rem;
    border-radius: 10px;
    border: 1px solid #e5e7eb;
    background: #f9fafb;
}

.pool-rule-status strong {
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.pool-rule-status span {
    font-size: 0.86rem;
    color: #4b5563;
}

.pool-rule-status--ok {
    border-color: #bbf7d0;
    background: #f0fdf4;
}

.pool-rule-status--ok strong {
    color: #166534;
}

.pool-rule-status--warning {
    border-color: #fde68a;
    background: #fffbeb;
}

.pool-rule-status--warning strong {
    color: #92400e;
}

.pool-rule-status--error {
    border-color: #fecaca;
    background: #fef2f2;
}

.pool-rule-status--error strong {
    color: #b91c1c;
}

.pool-rule-qualified {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-top: 0.45rem;
}

.pool-rule-qualified strong {
    color: #1f2937;
    font-size: 0.82rem;
}

.pool-rule-qualified-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.pool-rule-qualified-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.22rem 0.55rem;
    border-radius: 999px;
    background: #e5f3ff;
    color: #1d4ed8;
    font-size: 0.8rem;
    font-weight: 600;
}

.pool-rule-help {
    margin-top: -0.2rem;
    color: #6b7280;
    font-size: 0.82rem;
}

.pool-rule-targets {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    align-items: end;
}

.pool-rule-presets {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-top: 0.75rem;
    color: #6b7280;
    font-size: 0.85rem;
}

.pool-rule-preset {
    padding: 0.2rem 0.55rem;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    background: #fff;
    color: #374151;
    font-weight: 600;
    cursor: pointer;
}

.pool-rule-preset:hover {
    background: #f3f4f6;
}

.stage-actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.stage-actions-panel {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    padding: 0.95rem;
    border-radius: 12px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
}

.stage-actions-header {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.stage-actions-header span {
    color: #6b7280;
    font-size: 0.9rem;
}

.stage-action-list {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
}

.stage-action-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 0.85rem;
    border-radius: 12px;
    background: #fff;
    border: 1px solid #e5e7eb;
}

.stage-action-copy {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.stage-action-copy span {
    color: #6b7280;
    font-size: 0.88rem;
}

.stage-actions-hint {
    color: #92400e;
    font-size: 0.88rem;
}

.stage-message-error {
    color: #b00020;
    white-space: pre-wrap;
}

.stage-message-success {
    color: #1b5e20;
}

@media (max-width: 900px) {
    .config-grid {
        grid-template-columns: 1fr;
    }

    .config-actions {
        justify-content: flex-start;
    }
}
</style>
