package de.tsschulz.tt_tagebuch.app.ui

import android.content.Context
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Divider
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.ScrollableTabRow
import androidx.compose.material.Tab
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import de.tsschulz.tt_tagebuch.app.AppDependencies
import de.tsschulz.tt_tagebuch.app.pdf.shareFileWithMime
import de.tsschulz.tt_tagebuch.shared.api.models.ClubLeagueOptionDto
import de.tsschulz.tt_tagebuch.shared.api.models.ClubTeamCreateBody
import de.tsschulz.tt_tagebuch.shared.api.models.ClubTeamDto
import de.tsschulz.tt_tagebuch.shared.api.models.ClubTeamLineupRowDto
import de.tsschulz.tt_tagebuch.shared.api.models.ClubTeamUpdateBody
import de.tsschulz.tt_tagebuch.shared.api.models.LeaguePlayerStatDto
import de.tsschulz.tt_tagebuch.shared.api.models.Member
import de.tsschulz.tt_tagebuch.shared.api.models.TeamLineupAssignmentItem
import de.tsschulz.tt_tagebuch.shared.api.models.TeamLineupUpdateBody
import de.tsschulz.tt_tagebuch.shared.api.models.canWriteTeams
import de.tsschulz.tt_tagebuch.shared.i18n.MobileStrings
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Calendar
import java.util.GregorianCalendar

private enum class TeamEditorTab {
    Basic,
    Stats,
    Lineup,
    Documents,
    Jobs,
    MyTischtennis,
}

private data class MyTtUiStatus(
    val complete: Boolean,
    val partial: Boolean,
    val missingItemLabels: List<String>,
    val needsLeague: Boolean,
    val needsTeamId: Boolean,
)

private fun myTtStatus(team: ClubTeamDto, t: (String, String) -> String): MyTtUiStatus {
    val hasTeamId = !team.myTischtennisTeamId.isNullOrBlank()
    val hasLeague = team.league != null
    val hasPlanned = !team.plannedLeagueName.isNullOrBlank()
    val hasLeagueForWorkflow = hasLeague || hasPlanned
    val lg = team.league
    val hasLeagueConfig = hasLeague &&
        !lg?.myTischtennisGroupId.isNullOrBlank() &&
        !lg?.association.isNullOrBlank() &&
        !lg?.groupname.isNullOrBlank()

    val missing = mutableListOf<String>()
    if (!hasTeamId) missing.add(t("teamManagement.teamId", "MyTT-Team-ID"))
    if (!hasLeagueForWorkflow) missing.add(t("teamManagement.league", "Liga"))
    if (hasLeague && lg?.myTischtennisGroupId.isNullOrBlank()) {
        missing.add(t("teamManagement.groupId", "Gruppen-ID"))
    }
    if (hasLeague && lg?.association.isNullOrBlank()) {
        missing.add(t("teamManagement.association", "Verband"))
    }
    if (hasLeague && lg?.groupname.isNullOrBlank()) {
        missing.add(t("teamManagement.groupName", "Gruppenname"))
    }

    val complete = hasTeamId && hasLeagueConfig
    val partial = (hasTeamId || hasLeagueConfig || hasPlanned) && !complete
    return MyTtUiStatus(
        complete = complete,
        partial = partial,
        missingItemLabels = missing,
        needsLeague = !hasLeagueForWorkflow,
        needsTeamId = !hasTeamId,
    )
}

private fun isSecondHalfSeason(): Boolean {
    val now = GregorianCalendar()
    val seasonStart = GregorianCalendar(now.get(Calendar.YEAR), Calendar.JULY, 1, 0, 0, 0)
    if (seasonStart.after(now)) {
        seasonStart.add(Calendar.YEAR, -1)
    }
    val secondHalfStart = GregorianCalendar(seasonStart.get(Calendar.YEAR) + 1, Calendar.JANUARY, 1, 0, 0, 0)
    return now.timeInMillis >= secondHalfStart.timeInMillis
}

@Composable
internal fun TeamEditorScreen(
    dependencies: AppDependencies,
    clubId: Int,
    seasonId: Int,
    seasonLabel: String,
    initialTeamId: Int?,
    onBack: () -> Unit,
    onSaved: () -> Unit,
) {
    val languageCode = LocalLanguageCode.current
    fun t(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    val context = LocalContext.current
    val clubState by dependencies.clubManager.state.collectAsState()
    val canWrite = clubState.currentPermissions?.canWriteTeams() == true
    val scope = rememberCoroutineScope()

    val startedWithoutId = initialTeamId == null
    var team by remember(initialTeamId) { mutableStateOf<ClubTeamDto?>(null) }
    var loadingTeam by remember(initialTeamId) { mutableStateOf(initialTeamId != null) }
    var teamLoadError by remember { mutableStateOf<String?>(null) }

    var tabIndex by remember { mutableIntStateOf(0) }
    val tabs = remember(team?.id, team?.leagueId) {
        buildList {
            add(TeamEditorTab.Basic)
            if (team != null && (team!!.leagueId ?: 0) > 0) add(TeamEditorTab.Stats)
            if (team != null) {
                add(TeamEditorTab.Lineup)
                add(TeamEditorTab.Documents)
                add(TeamEditorTab.Jobs)
                add(TeamEditorTab.MyTischtennis)
            }
        }
    }

    LaunchedEffect(tabs.size) {
        if (tabIndex >= tabs.size) tabIndex = 0
    }

    var pendingDocType by remember { mutableStateOf<String?>(null) }

    var formName by remember { mutableStateOf("") }
    var formLeagueId by remember { mutableStateOf<Int?>(null) }
    var formPlanned by remember { mutableStateOf("") }
    var formGender by remember { mutableStateOf("open") }
    var formAge by remember { mutableStateOf("adult") }
    var leagues by remember(clubId, seasonId) { mutableStateOf<List<ClubLeagueOptionDto>>(emptyList()) }
    var leagueMenu by remember { mutableStateOf(false) }
    var genderMenu by remember { mutableStateOf(false) }
    var ageMenu by remember { mutableStateOf(false) }
    var saving by remember { mutableStateOf(false) }
    var info by remember { mutableStateOf<String?>(null) }

    var playerStats by remember { mutableStateOf<List<LeaguePlayerStatDto>>(emptyList()) }
    var loadingStats by remember { mutableStateOf(false) }

    var clubMembers by remember { mutableStateOf<List<Member>>(emptyList()) }
    var lineupHalf by remember { mutableStateOf(if (isSecondHalfSeason()) "second_half" else "first_half") }
    var lineupRows by remember { mutableStateOf<List<ClubTeamLineupRowDto>>(emptyList()) }
    var loadingLineup by remember { mutableStateOf(false) }
    var savingLineup by remember { mutableStateOf(false) }

    var documents by remember { mutableStateOf<List<de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto>>(emptyList()) }
    var loadingDocs by remember { mutableStateOf(false) }
    var parsingDocId by remember { mutableStateOf<Int?>(null) }

    var schedulerLoaded by remember { mutableStateOf(false) }
    var schedulerBlock by remember {
        mutableStateOf<de.tsschulz.tt_tagebuch.shared.api.models.SchedulerJobBlockDto?>(
            null,
        )
    }

    var myTtUrl by remember { mutableStateOf("") }
    var myTtLeagueUrl by remember { mutableStateOf("") }
    var myTtBusy by remember { mutableStateOf(false) }
    var createLeague by remember { mutableStateOf(true) }
    var createSeason by remember { mutableStateOf(true) }
    var createSeasonLeague by remember { mutableStateOf(true) }

    fun effectiveTeam(): ClubTeamDto? = team

    fun reloadDocuments() {
        val id = team?.id ?: return
        scope.launch {
            loadingDocs = true
            runCatching {
                documents = withContext(Dispatchers.IO) {
                    dependencies.teamDocumentsApi.listByClubTeam(id)
                }
            }
            loadingDocs = false
        }
    }

    fun reloadLineup() {
        val id = team?.id ?: return
        scope.launch {
            loadingLineup = true
            runCatching {
                lineupRows = withContext(Dispatchers.IO) {
                    dependencies.clubTeamsApi.getLineup(id, lineupHalf)
                }
            }
            loadingLineup = false
        }
    }

    fun reloadMembers() {
        scope.launch {
            runCatching {
                clubMembers = withContext(Dispatchers.IO) {
                    dependencies.membersApi.listMembers(clubId, showAll = true)
                }
            }
        }
    }

    LaunchedEffect(initialTeamId, clubId, seasonId) {
        runCatching {
            leagues = withContext(Dispatchers.IO) {
                dependencies.clubTeamsApi.listLeagues(clubId, seasonId).sortedBy { it.name.lowercase() }
            }
            if (startedWithoutId) {
                formName = ""
                formLeagueId = null
                formPlanned = ""
                formGender = "open"
                formAge = "adult"
                loadingTeam = false
            } else {
                loadingTeam = true
                teamLoadError = null
                val loaded = withContext(Dispatchers.IO) {
                    dependencies.clubTeamsApi.getClubTeam(initialTeamId!!)
                }
                team = loaded
                formName = loaded.name
                formLeagueId = loaded.leagueId
                formPlanned = loaded.plannedLeagueName.orEmpty()
                formGender = loaded.teamGender?.takeIf { it.isNotBlank() } ?: "open"
                formAge = loaded.teamAgeGroup?.takeIf { it.isNotBlank() } ?: "adult"
                loadingTeam = false
            }
        }.onFailure {
            teamLoadError = it.message ?: t("mobile.teamLoadError", "Laden fehlgeschlagen")
            loadingTeam = false
        }
    }

    LaunchedEffect(team?.id, tabIndex, tabs) {
        val currentTab = tabs.getOrNull(tabIndex) ?: return@LaunchedEffect
        if (team == null) return@LaunchedEffect
        when (currentTab) {
            TeamEditorTab.Stats -> {
                val lid = team!!.leagueId ?: return@LaunchedEffect
                loadingStats = true
                runCatching {
                    playerStats = withContext(Dispatchers.IO) {
                        dependencies.matchesApi.getLeaguePlayerStats(clubId, lid, seasonId)
                    }
                }
                loadingStats = false
            }
            TeamEditorTab.Lineup -> {
                reloadMembers()
                reloadLineup()
            }
            TeamEditorTab.Documents -> reloadDocuments()
            TeamEditorTab.Jobs -> {
                if (!schedulerLoaded) {
                    runCatching {
                        val env = withContext(Dispatchers.IO) {
                            dependencies.apiLogsApi.getSchedulerLastExecutions(clubId)
                        }
                        schedulerBlock = env.data?.matchResults
                        schedulerLoaded = true
                    }
                }
            }
            else -> {}
        }
    }

    val documentPicker = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.OpenDocument(),
    ) { uri ->
        val id = team?.id ?: return@rememberLauncherForActivityResult
        val type = pendingDocType ?: return@rememberLauncherForActivityResult
        if (uri == null) return@rememberLauncherForActivityResult
        scope.launch {
            saving = true
            runCatching {
                val bytes = withContext(Dispatchers.IO) {
                    context.contentResolver.openInputStream(uri)!!.use { it.readBytes() }
                }
                val name = uri.lastPathSegment ?: "upload.bin"
                val mime = context.contentResolver.getType(uri) ?: "application/octet-stream"
                withContext(Dispatchers.IO) {
                    dependencies.teamDocumentsApi.upload(id, type, bytes, name, mime)
                }
                reloadDocuments()
            }.onFailure {
                info = it.message ?: t("common.error", "Fehler")
            }
            saving = false
        }
    }

    Column(Modifier.fillMaxSize().padding(16.dp)) {
        Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
            IconButton(onClick = onBack) {
                Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
            }
            Text(
                if (team == null) t("mobile.teamNew", "Neue Mannschaft") else (team?.name ?: "…"),
                style = MaterialTheme.typography.h6,
                fontWeight = FontWeight.SemiBold,
                modifier = Modifier.fillMaxWidth(),
            )
        }

        if (loadingTeam) {
            CircularProgressIndicator(Modifier.padding(top = 24.dp))
            return@Column
        }
        teamLoadError?.let {
            Text(it, color = MaterialTheme.colors.error)
            return@Column
        }

        ScrollableTabRow(
            selectedTabIndex = tabIndex.coerceIn(0, (tabs.size - 1).coerceAtLeast(0)),
            edgePadding = 0.dp,
            modifier = Modifier.fillMaxWidth(),
        ) {
            tabs.forEachIndexed { i, tab ->
                Tab(
                    selected = tabIndex == i,
                    onClick = { tabIndex = i },
                    text = {
                        Text(
                            when (tab) {
                                TeamEditorTab.Basic -> t("mobile.teamEditorTabBasic", "Stammdaten")
                                TeamEditorTab.Stats -> t("mobile.teamEditorTabStats", "Spieler")
                                TeamEditorTab.Lineup -> t("mobile.teamEditorTabLineup", "Aufstellung")
                                TeamEditorTab.Documents -> t("mobile.teamEditorTabDocs", "Dokumente")
                                TeamEditorTab.Jobs -> t("mobile.teamEditorTabJobs", "Jobs")
                                TeamEditorTab.MyTischtennis -> "MyTT"
                            },
                        )
                    },
                )
            }
        }

        Spacer(Modifier.height(12.dp))

        Box(Modifier.weight(1f).fillMaxWidth()) {
        when (tabs.getOrNull(tabIndex)) {
            TeamEditorTab.Basic -> BasicTab(
                t = ::t,
                canWrite = canWrite,
                isCreateMode = team == null,
                formName = formName,
                onName = { formName = it },
                formLeagueId = formLeagueId,
                leagues = leagues,
                leagueMenu = leagueMenu,
                onLeagueMenu = { leagueMenu = it },
                onLeaguePick = { formLeagueId = it; leagueMenu = false },
                formPlanned = formPlanned,
                onPlanned = { formPlanned = it },
                formGender = formGender,
                formAge = formAge,
                genderMenu = genderMenu,
                onGenderMenu = { genderMenu = it },
                ageMenu = ageMenu,
                onAgeMenu = { ageMenu = it },
                onGenderPick = { formGender = it; genderMenu = false },
                onAgePick = { formAge = it; ageMenu = false },
                saving = saving,
                team = team,
                onSave = {
                    if (!canWrite || formName.isBlank()) return@BasicTab
                    scope.launch {
                        saving = true
                        runCatching {
                            if (team == null) {
                                val created = withContext(Dispatchers.IO) {
                                    dependencies.clubTeamsApi.createClubTeam(
                                        clubId,
                                        ClubTeamCreateBody(
                                            name = formName.trim(),
                                            leagueId = formLeagueId,
                                            seasonId = seasonId,
                                            teamGender = formGender,
                                            teamAgeGroup = formAge,
                                            plannedLeagueName = formPlanned.trim().ifBlank { null },
                                        ),
                                    )
                                }
                                team = created
                                withContext(Dispatchers.IO) {
                                    dependencies.scheduleManager.loadClubTeams(clubId)
                                }
                                onSaved()
                                tabIndex = 0
                            } else {
                                val id = team!!.id
                                val updated = withContext(Dispatchers.IO) {
                                    dependencies.clubTeamsApi.updateClubTeam(
                                        id,
                                        ClubTeamUpdateBody(
                                            name = formName.trim(),
                                            leagueId = formLeagueId,
                                            seasonId = seasonId,
                                            teamGender = formGender,
                                            teamAgeGroup = formAge,
                                            plannedLeagueName = formPlanned.trim().ifBlank { null },
                                        ),
                                    )
                                }
                                team = updated
                                withContext(Dispatchers.IO) {
                                    dependencies.scheduleManager.loadClubTeams(clubId)
                                }
                                onSaved()
                            }
                        }.onFailure { ex ->
                            if (ex is CancellationException) throw ex
                            info = ex.message ?: t("common.error", "Fehler")
                        }
                        saving = false
                    }
                },
            )

            TeamEditorTab.Stats -> StatsTab(
                t = ::t,
                loading = loadingStats,
                stats = playerStats,
                secondHalf = isSecondHalfSeason(),
                members = clubMembers,
                onRefresh = {
                    val lid = team?.leagueId ?: return@StatsTab
                    scope.launch {
                        loadingStats = true
                        runCatching {
                            playerStats = withContext(Dispatchers.IO) {
                                dependencies.matchesApi.getLeaguePlayerStats(clubId, lid, seasonId)
                            }
                        }
                        loadingStats = false
                    }
                },
            )

            TeamEditorTab.Lineup -> LineupTab(
                t = ::t,
                context = context,
                canWrite = canWrite,
                team = team!!,
                seasonLabel = seasonLabel,
                members = clubMembers,
                lineupHalf = lineupHalf,
                onHalfChange = { lineupHalf = it; reloadLineup() },
                loading = loadingLineup,
                saving = savingLineup,
                lineupRows = lineupRows,
                onPersist = { assignments ->
                    scope.launch {
                        savingLineup = true
                        runCatching {
                            lineupRows = withContext(Dispatchers.IO) {
                                dependencies.clubTeamsApi.updateLineup(
                                    team!!.id,
                                    TeamLineupUpdateBody(assignments = assignments, lineupHalf = lineupHalf),
                                )
                            }
                        }.onFailure { ex ->
                            if (ex is CancellationException) throw ex
                            info = ex.message
                        }
                        savingLineup = false
                    }
                },
                onReload = {
                    reloadMembers()
                    reloadLineup()
                },
            )

            TeamEditorTab.Documents -> DocumentsTab(
                t = ::t,
                canWrite = canWrite,
                team = team!!,
                documents = documents,
                loading = loadingDocs,
                parsingId = parsingDocId,
                onPickUpload = { docType ->
                    pendingDocType = docType
                    documentPicker.launch(arrayOf("application/pdf", "text/*", "text/csv", "application/msword", "*/*"))
                },
                onParse = { doc ->
                    val lid = team!!.leagueId
                    if (lid == null) {
                        info = t("teamManagement.missingLeagueForTeam", "Liga erforderlich zum Parsen.")
                        return@DocumentsTab
                    }
                    scope.launch {
                        parsingDocId = doc.id
                        runCatching {
                            withContext(Dispatchers.IO) {
                                dependencies.teamDocumentsApi.parse(doc.id, lid)
                            }
                            info = t("mobile.teamDocParseDone", "Dokument verarbeitet.")
                        }.onFailure {
                            info = it.message
                        }
                        parsingDocId = null
                    }
                },
                onOpen = { doc ->
                    scope.launch {
                        runCatching {
                            val bytes = withContext(Dispatchers.IO) {
                                dependencies.teamDocumentsApi.download(doc.id)
                            }
                            val ext = when {
                                doc.mimeType?.contains("pdf") == true -> ".pdf"
                                doc.mimeType?.contains("text") == true -> ".txt"
                                else -> ""
                            }
                            val f = File(context.cacheDir, "team-doc-${doc.id}$ext")
                            f.writeBytes(bytes)
                            shareFileWithMime(
                                context,
                                f,
                                doc.mimeType ?: "application/octet-stream",
                                doc.originalFileName,
                            )
                        }.onFailure {
                            info = it.message
                        }
                    }
                },
            )

            TeamEditorTab.Jobs -> JobsTab(t = ::t, block = schedulerBlock, teamId = team!!.id)

            TeamEditorTab.MyTischtennis -> MyTtTab(
                t = ::t,
                team = team!!,
                busy = myTtBusy,
                url = myTtUrl,
                onUrl = { myTtUrl = it },
                leagueUrl = myTtLeagueUrl,
                onLeagueUrl = { myTtLeagueUrl = it },
                createLeague = createLeague,
                onCreateLeague = { createLeague = it },
                createSeason = createSeason,
                onCreateSeason = { createSeason = it },
                createSeasonLeague = createSeasonLeague,
                onCreateSeasonLeague = { createSeasonLeague = it },
                onParse = {
                    scope.launch {
                        myTtBusy = true
                        runCatching {
                            withContext(Dispatchers.IO) {
                                dependencies.myTischtennisApi.parseUrl(myTtUrl.trim())
                            }
                            info = t("mobile.teamMyTtParseOk", "URL geparst.")
                        }.onFailure { info = it.message }
                        myTtBusy = false
                    }
                },
                onConfigureTeam = {
                    scope.launch {
                        myTtBusy = true
                        runCatching {
                            withContext(Dispatchers.IO) {
                                dependencies.myTischtennisApi.configureTeam(
                                    de.tsschulz.tt_tagebuch.shared.api.models.MyTtConfigureTeamBody(
                                        url = myTtUrl.trim(),
                                        clubTeamId = team!!.id,
                                        createLeague = createLeague,
                                        createSeason = createSeason,
                                    ),
                                )
                            }
                            team = withContext(Dispatchers.IO) {
                                dependencies.clubTeamsApi.getClubTeam(team!!.id)
                            }
                            onSaved()
                            info = t("mobile.teamMyTtConfigured", "Team verknüpft.")
                        }.onFailure { info = it.message }
                        myTtBusy = false
                    }
                },
                onConfigureLeague = {
                    scope.launch {
                        myTtBusy = true
                        runCatching {
                            withContext(Dispatchers.IO) {
                                dependencies.myTischtennisApi.configureLeague(
                                    de.tsschulz.tt_tagebuch.shared.api.models.MyTtConfigureLeagueBody(
                                        url = myTtLeagueUrl.trim(),
                                        createSeason = createSeasonLeague,
                                    ),
                                )
                            }
                            info = t("mobile.teamMyTtLeagueConfigured", "Liga verknüpft.")
                        }.onFailure { info = it.message }
                        myTtBusy = false
                    }
                },
                onFetch = {
                    scope.launch {
                        myTtBusy = true
                        runCatching {
                            val start = withContext(Dispatchers.IO) {
                                dependencies.myTischtennisApi.startFetchTeamDataJob(team!!.id)
                            }
                            val jobId = start.jobId ?: error("jobId")
                            var done = false
                            repeat(120) {
                                delay(2000)
                                val st = withContext(Dispatchers.IO) {
                                    dependencies.myTischtennisApi.getFetchTeamDataJob(jobId)
                                }
                                val status = st.job?.status ?: return@repeat
                                if (status == "completed" || status == "failed") {
                                    done = true
                                    if (status == "failed") {
                                        info = st.job?.error ?: t("mobile.teamMyTtFetchFail", "Abruf fehlgeschlagen")
                                    } else {
                                        info = t("mobile.teamMyTtFetchOk", "Daten abgerufen.")
                                        team = withContext(Dispatchers.IO) {
                                            dependencies.clubTeamsApi.getClubTeam(team!!.id)
                                        }
                                        onSaved()
                                    }
                                    return@launch
                                }
                            }
                            if (!done) {
                                info = t("mobile.teamMyTtFetchTimeout", "Zeitüberschreitung beim Abruf.")
                            }
                        }.onFailure {
                            if (it !is CancellationException) info = it.message
                        }
                        myTtBusy = false
                    }
                },
            )

            null -> {}
        }
        }
    }

    info?.let { msg ->
        StableAlertDialog(
            onDismissRequest = { info = null },
            title = { Text(t("common.info", "Hinweis")) },
            text = { Text(msg) },
            confirmButton = { TextButton(onClick = { info = null }) { Text(t("common.ok", "OK")) } },
        )
    }
}

@Composable
private fun BasicTab(
    t: (String, String) -> String,
    canWrite: Boolean,
    isCreateMode: Boolean,
    formName: String,
    onName: (String) -> Unit,
    formLeagueId: Int?,
    leagues: List<ClubLeagueOptionDto>,
    leagueMenu: Boolean,
    onLeagueMenu: (Boolean) -> Unit,
    onLeaguePick: (Int?) -> Unit,
    formPlanned: String,
    onPlanned: (String) -> Unit,
    formGender: String,
    formAge: String,
    genderMenu: Boolean,
    onGenderMenu: (Boolean) -> Unit,
    ageMenu: Boolean,
    onAgeMenu: (Boolean) -> Unit,
    onGenderPick: (String) -> Unit,
    onAgePick: (String) -> Unit,
    saving: Boolean,
    team: ClubTeamDto?,
    onSave: () -> Unit,
) {
    val myStatus = team?.let { myTtStatus(it, t) }
    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState()),
        verticalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        if (myStatus != null && myStatus.missingItemLabels.isNotEmpty() && !myStatus.complete) {
            Card(elevation = 1.dp, modifier = Modifier.fillMaxWidth()) {
                Column(Modifier.padding(12.dp)) {
                    Text(t("teamManagement.missingConfigSummary", "Offene Punkte"), fontWeight = FontWeight.SemiBold)
                    myStatus.missingItemLabels.forEach { line ->
                        Text("• $line", style = MaterialTheme.typography.caption)
                    }
                }
            }
        }
        OutlinedTextField(
            value = formName,
            onValueChange = onName,
            label = { Text(t("mobile.teamName", "Name")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
            enabled = canWrite,
        )
        Text(t("mobile.league", "Liga"), style = MaterialTheme.typography.caption)
        Box {
            OutlinedButton(
                onClick = { onLeagueMenu(true) },
                modifier = Modifier.fillMaxWidth(),
                enabled = canWrite,
            ) {
                Text(
                    formLeagueId?.let { id -> leagues.find { it.id == id }?.name }
                        ?: t("mobile.noLeague", "Keine Liga"),
                )
            }
            DropdownMenu(expanded = leagueMenu, onDismissRequest = { onLeagueMenu(false) }) {
                DropdownMenuItem(onClick = { onLeaguePick(null); onLeagueMenu(false) }) {
                    Text(t("mobile.noLeague", "Keine Liga"))
                }
                leagues.forEach { lg ->
                    DropdownMenuItem(onClick = { onLeaguePick(lg.id); onLeagueMenu(false) }) {
                        Text(lg.name)
                    }
                }
            }
        }
        OutlinedTextField(
            value = formPlanned,
            onValueChange = onPlanned,
            label = { Text(t("mobile.plannedLeague", "Geplante Liga")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
            enabled = canWrite,
        )
        Text(t("mobile.teamGenderShort", "Geschlecht"), style = MaterialTheme.typography.caption)
        Box {
            OutlinedButton(onClick = { onGenderMenu(true) }, enabled = canWrite, modifier = Modifier.fillMaxWidth()) {
                Text(formGender)
            }
            DropdownMenu(expanded = genderMenu, onDismissRequest = { onGenderMenu(false) }) {
                listOf("open", "female").forEach { g ->
                    DropdownMenuItem(onClick = { onGenderPick(g); onGenderMenu(false) }) { Text(g) }
                }
            }
        }
        Text(t("mobile.teamAgeShort", "Altersklasse"), style = MaterialTheme.typography.caption)
        Box {
            OutlinedButton(onClick = { onAgeMenu(true) }, enabled = canWrite, modifier = Modifier.fillMaxWidth()) {
                Text(formAge)
            }
            DropdownMenu(expanded = ageMenu, onDismissRequest = { onAgeMenu(false) }) {
                listOf("adult", "J19", "J17", "J15", "J13", "J11").forEach { a ->
                    DropdownMenuItem(onClick = { onAgePick(a); onAgeMenu(false) }) { Text(a) }
                }
            }
        }
        if (canWrite) {
            Button(onClick = onSave, enabled = !saving && formName.isNotBlank(), modifier = Modifier.fillMaxWidth()) {
                if (saving) CircularProgressIndicator(strokeWidth = 2.dp, modifier = Modifier.height(20.dp))
                else Text(if (isCreateMode) t("mobile.teamCreate", "Anlegen") else t("common.save", "Speichern"))
            }
        }
    }
}

@Composable
private fun StatsTab(
    t: (String, String) -> String,
    loading: Boolean,
    stats: List<LeaguePlayerStatDto>,
    secondHalf: Boolean,
    members: List<Member>,
    onRefresh: () -> Unit,
) {
    val byId = remember(members) { members.associateBy { it.id } }
    Column(Modifier.fillMaxSize()) {
        TextButton(onClick = onRefresh, enabled = !loading) {
            Text(t("teamManagement.refreshStats", "Aktualisieren"))
        }
        if (loading) CircularProgressIndicator()
        else if (stats.isEmpty()) {
            Text(t("teamManagement.noPlayerStats", "Keine Spielerstatistik."))
        } else {
            LazyColumn {
                item {
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                        Text(t("teamManagement.player", "Spieler"), fontWeight = FontWeight.SemiBold)
                        Text("(Q)TTR", fontWeight = FontWeight.SemiBold)
                        Text(t("teamManagement.season", "Saison"), fontWeight = FontWeight.SemiBold)
                        Text(
                            if (secondHalf) t("teamManagement.secondHalf", "Rück.") else t("teamManagement.firstHalf", "Vorr."),
                            fontWeight = FontWeight.SemiBold,
                        )
                    }
                }
                items(stats, key = { it.memberId }) { s ->
                    val m = byId[s.memberId]
                    val qttrLabel = m?.qttr?.takeIf { it > 0 }?.toString() ?: "–"
                    Column(Modifier.padding(vertical = 6.dp)) {
                        Text("${s.firstName} ${s.lastName}", fontWeight = FontWeight.Medium)
                        Text(
                            "(Q)TTR: $qttrLabel · Saison: ${s.totalSeason} · " +
                                if (secondHalf) "RR: ${s.totalSecondHalf}" else "VR: ${s.totalFirstHalf}",
                            style = MaterialTheme.typography.caption,
                        )
                    }
                }
            }
        }
    }
}

@Composable
private fun LineupTab(
    t: (String, String) -> String,
    context: Context,
    canWrite: Boolean,
    team: ClubTeamDto,
    seasonLabel: String,
    members: List<Member>,
    lineupHalf: String,
    onHalfChange: (String) -> Unit,
    loading: Boolean,
    saving: Boolean,
    lineupRows: List<ClubTeamLineupRowDto>,
    onPersist: (List<TeamLineupAssignmentItem>) -> Unit,
    onReload: () -> Unit,
) {
    val tAge = TeamEditorLineupLogic.configuredTeamAgeGroup(team.teamAgeGroup, team.league?.name)
    val tGender = TeamEditorLineupLogic.configuredTeamGender(team.teamGender, team.league?.name)
    val groups = remember(members, team, seasonLabel) {
        TeamEditorLineupLogic.buildLineupGroups(
            members = members,
            teamAgeGroup = tAge,
            teamGender = tGender,
            seasonLabel = seasonLabel,
            labelAdults = t("members.adults", "Erwachsene"),
            labelUnknown = t("unknown", "Unbekannt"),
        )
    }
    var ordered by remember(lineupRows, members, lineupHalf) {
        mutableStateOf(
            lineupRows.sortedBy { it.position }.mapNotNull { row ->
                row.member ?: members.find { it.id == row.memberId }
            },
        )
    }

    val selectedIds = ordered.map { it.id }.toSet()
    val availableCount = remember(groups, ordered) {
        val ids = ordered.map { it.id }.toSet()
        groups.sumOf { g -> g.members.count { it.member.id !in ids } }
    }

    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState()),
        verticalArrangement = Arrangement.spacedBy(10.dp),
    ) {
        Card(elevation = 1.dp, modifier = Modifier.fillMaxWidth(), backgroundColor = MaterialTheme.colors.surface) {
            Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
                Text(
                    t("mobile.teamLineupIntroTitle", "Mannschaftsmeldung"),
                    fontWeight = FontWeight.SemiBold,
                    style = MaterialTheme.typography.subtitle1,
                )
                Text(
                    t(
                        "mobile.teamLineupIntroBody",
                        "Spieler unten unter „Weitere Spieler“ mit Hinzufügen in die Meldung übernehmen. Reihenfolge mit ↑/↓ ändern, mit − wieder entfernen. Änderungen werden gespeichert.",
                    ),
                    style = MaterialTheme.typography.caption,
                    color = MaterialTheme.colors.onSurface.copy(alpha = 0.85f),
                )
                if (!canWrite) {
                    Text(
                        t("mobile.teamLineupReadOnly", "Nur Lesezugriff: Meldung kann nicht geändert werden."),
                        style = MaterialTheme.typography.caption,
                        color = MaterialTheme.colors.error,
                    )
                }
            }
        }

        Row(Modifier.horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
            Text(t("common.period", "Halbserie"), modifier = Modifier.align(Alignment.CenterVertically))
            listOf("first_half" to "VR", "second_half" to "RR").forEach { (v, label) ->
                Button(
                    onClick = { onHalfChange(v) },
                    enabled = !saving && lineupHalf != v,
                ) { Text(label) }
            }
            TextButton(onClick = onReload, enabled = !loading) {
                Text(t("teamManagement.refreshStats", "Aktualisieren"))
            }
        }
        if (loading) CircularProgressIndicator(Modifier.padding(8.dp))

        Text(
            t("teamManagement.selectedLineup", "Aktuelle Meldung") + " (${ordered.size})",
            fontWeight = FontWeight.SemiBold,
        )
        if (ordered.isEmpty()) {
            Text(t("teamManagement.lineupEmpty", "Noch niemand gemeldet."))
        } else {
            ordered.forEachIndexed { index, m ->
                Row(
                    Modifier.fillMaxWidth(),
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceBetween,
                ) {
                    Text("${index + 1}. ${m.firstName} ${m.lastName} (${TeamEditorLineupLogic.lineupRatingLabel(m)})")
                    Row {
                        TextButton(
                            onClick = {
                                if (index <= 0) return@TextButton
                                val next = ordered.toMutableList().also { it.swap(index, index - 1) }
                                val warn = TeamEditorLineupLogic.lineupGapViolationMessage(next) { hi, lo ->
                                    t("mobile.lineupGapWarn", "QTTR-Abstand >30: $hi über $lo")
                                }
                                if (warn != null) {
                                    android.widget.Toast.makeText(context, warn, android.widget.Toast.LENGTH_LONG).show()
                                    return@TextButton
                                }
                                ordered = next
                                onPersist(next.mapIndexed { i, mem -> TeamLineupAssignmentItem(mem.id, i + 1) })
                            },
                            enabled = canWrite && !saving && index > 0,
                        ) { Text("↑") }
                        TextButton(
                            onClick = {
                                if (index >= ordered.lastIndex) return@TextButton
                                val next = ordered.toMutableList().also { it.swap(index, index + 1) }
                                val warn = TeamEditorLineupLogic.lineupGapViolationMessage(next) { hi, lo ->
                                    t("mobile.lineupGapWarn", "QTTR-Abstand >30: $hi über $lo")
                                }
                                if (warn != null) {
                                    android.widget.Toast.makeText(context, warn, android.widget.Toast.LENGTH_LONG).show()
                                    return@TextButton
                                }
                                ordered = next
                                onPersist(next.mapIndexed { i, mem -> TeamLineupAssignmentItem(mem.id, i + 1) })
                            },
                            enabled = canWrite && !saving && index < ordered.lastIndex,
                        ) { Text("↓") }
                        TextButton(
                            onClick = {
                                val next = ordered.toMutableList().also { it.removeAt(index) }
                                ordered = next
                                onPersist(next.mapIndexed { i, mem -> TeamLineupAssignmentItem(mem.id, i + 1) })
                            },
                            enabled = canWrite && !saving,
                        ) { Text("−") }
                    }
                }
            }
        }

        Divider()

        Text(
            t("teamManagement.availableLineupMembers", "Weitere Spieler") + " ($availableCount)",
            fontWeight = FontWeight.SemiBold,
        )
        if (groups.isEmpty()) {
            Card(elevation = 0.dp, modifier = Modifier.fillMaxWidth(), backgroundColor = MaterialTheme.colors.surface) {
                Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
                    Text(
                        t("mobile.teamLineupNoEligibleTitle", "Keine meldefähigen Spieler"),
                        fontWeight = FontWeight.Medium,
                    )
                    Text(
                        t(
                            "mobile.teamLineupNoEligibleBody",
                            "Es werden nur aktive Vereinsmitglieder angezeigt, die zur Alters-/Geschlechtsklasse dieser Mannschaft passen (Geburtsdatum, ggf. Erwachsenen-Freigabe bei Jugendlichen in Erwachsenen-Mannschaften).",
                        ),
                        style = MaterialTheme.typography.caption,
                        color = MaterialTheme.colors.onSurface.copy(alpha = 0.82f),
                    )
                }
            }
        } else if (availableCount == 0) {
            Text(
                t(
                    "mobile.teamLineupAllInLineup",
                    "Alle passenden Spieler sind bereits in der Meldung – oder es gibt keine weiteren passenden Mitglieder.",
                ),
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.82f),
            )
        }
        groups.forEach { g ->
            val rows = g.members.filter { it.member.id !in selectedIds }
            if (rows.isEmpty()) return@forEach
            Text(g.label, fontWeight = FontWeight.Medium, modifier = Modifier.padding(top = 4.dp))
            rows.forEach { row ->
                Row(
                    Modifier
                        .fillMaxWidth()
                        .padding(vertical = 4.dp),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    Column(Modifier.weight(1f)) {
                        Text("${row.member.firstName} ${row.member.lastName}")
                        Text(
                            "${row.memberAgeGroupLabel} · ${row.lineupRatingLabel} · ${row.eligibilityLabel}",
                            style = MaterialTheme.typography.caption,
                        )
                    }
                    OutlinedButton(
                        onClick = {
                            val next = ordered + row.member
                            val warn = TeamEditorLineupLogic.lineupGapViolationMessage(next) { hi, lo ->
                                t("mobile.lineupGapWarn", "QTTR-Abstand >30: $hi über $lo")
                            }
                            if (warn != null) {
                                android.widget.Toast.makeText(context, warn, android.widget.Toast.LENGTH_LONG).show()
                                return@OutlinedButton
                            }
                            ordered = next
                            onPersist(next.mapIndexed { i, mem -> TeamLineupAssignmentItem(mem.id, i + 1) })
                        },
                        enabled = canWrite && !saving,
                    ) {
                        Text(t("mobile.teamLineupAddToLineup", "Hinzufügen"))
                    }
                }
            }
        }

        Divider()

        Card(elevation = 0.dp, modifier = Modifier.fillMaxWidth(), backgroundColor = MaterialTheme.colors.surface) {
            Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
                Text(
                    t("mobile.teamPlanningTitle", "Mannschafts-Planung"),
                    fontWeight = FontWeight.Medium,
                )
                Text(
                    t(
                        "mobile.teamPlanningBody",
                        "Die übergreifende Planung (Pool „Möchte spielen“, mehrere Mannschaften) findest du in der Team-Verwaltung unter dem Reiter „Planung“. Hier pflegst du die Meldung nur für diese eine Mannschaft.",
                    ),
                    style = MaterialTheme.typography.caption,
                    color = MaterialTheme.colors.onSurface.copy(alpha = 0.82f),
                )
            }
        }
    }
}

private fun <T> MutableList<T>.swap(i: Int, j: Int) {
    val tmp = this[i]
    this[i] = this[j]
    this[j] = tmp
}

@Composable
private fun DocumentsTab(
    t: (String, String) -> String,
    canWrite: Boolean,
    team: ClubTeamDto,
    documents: List<de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto>,
    loading: Boolean,
    parsingId: Int?,
    onPickUpload: (String) -> Unit,
    onParse: (de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto) -> Unit,
    onOpen: (de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto) -> Unit,
) {
    fun latest(type: String) = documents.filter { it.documentType == type }.maxByOrNull { it.id }
    Column(Modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(12.dp)) {
        if (loading) CircularProgressIndicator()
        DocCard(
            title = t("teamManagement.codeList", "Meldeliste"),
            latest = latest("code_list"),
            canWrite = canWrite,
            parsingId = parsingId,
            onUpload = { onPickUpload("code_list") },
            onParse = onParse,
            onOpen = onOpen,
            t = t,
        )
        DocCard(
            title = t("teamManagement.pinList", "PIN-Liste"),
            latest = latest("pin_list"),
            canWrite = canWrite,
            parsingId = parsingId,
            onUpload = { onPickUpload("pin_list") },
            onParse = onParse,
            onOpen = onOpen,
            t = t,
        )
    }
}

@Composable
private fun DocCard(
    title: String,
    latest: de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto?,
    canWrite: Boolean,
    parsingId: Int?,
    onUpload: () -> Unit,
    onParse: (de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto) -> Unit,
    onOpen: (de.tsschulz.tt_tagebuch.shared.api.models.TeamDocumentDto) -> Unit,
    t: (String, String) -> String,
) {
    Card(elevation = 1.dp, modifier = Modifier.fillMaxWidth()) {
        Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
            Text(title, fontWeight = FontWeight.SemiBold)
            Text(
                latest?.createdAt ?: t("teamManagement.noDocumentUploadYet", "Noch kein Upload"),
                style = MaterialTheme.typography.caption,
            )
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                if (canWrite) {
                    Button(onClick = onUpload) { Text(t("teamManagement.uploadNewVersion", "Hochladen")) }
                }
                if (latest != null) {
                    TextButton(onClick = { onOpen(latest) }) {
                        Text(t("teamManagement.openDocument", "Öffnen"))
                    }
                    TextButton(
                        onClick = { onParse(latest) },
                        enabled = parsingId != latest.id,
                    ) {
                        Text(t("teamManagement.parseDocument", "Parsen"))
                    }
                }
            }
        }
    }
}

@Composable
private fun JobsTab(
    t: (String, String) -> String,
    block: de.tsschulz.tt_tagebuch.shared.api.models.SchedulerJobBlockDto?,
    teamId: Int,
) {
    val detail = block?.teamDetails?.find { it.clubTeamId == teamId }
    Column {
        Text(t("teamManagement.automaticJobs", "Automatische Jobs"), fontWeight = FontWeight.SemiBold)
        if (detail == null) {
            Text(t("teamManagement.noAutomaticUpdate", "Keine Job-Daten für diese Mannschaft."))
        } else {
            Text("${t("teamManagement.lastUpdated", "Zuletzt")}: ${detail.lastRun ?: "–"}")
            Text(
                "${t("teamManagement.status", "Status")}: " +
                    if (detail.success) t("teamManagement.successful", "OK") else t("teamManagement.error", "Fehler"),
            )
        }
    }
}

@Composable
private fun MyTtTab(
    t: (String, String) -> String,
    team: ClubTeamDto,
    busy: Boolean,
    url: String,
    onUrl: (String) -> Unit,
    leagueUrl: String,
    onLeagueUrl: (String) -> Unit,
    createLeague: Boolean,
    onCreateLeague: (Boolean) -> Unit,
    createSeason: Boolean,
    onCreateSeason: (Boolean) -> Unit,
    createSeasonLeague: Boolean,
    onCreateSeasonLeague: (Boolean) -> Unit,
    onParse: () -> Unit,
    onConfigureTeam: () -> Unit,
    onConfigureLeague: () -> Unit,
    onFetch: () -> Unit,
) {
    val st = myTtStatus(team, t)
    Column(Modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp)) {
        Text(
            when {
                st.complete -> t("teamManagement.fullyConfigured", "Vollständig")
                st.partial -> t("teamManagement.partiallyConfigured", "Teilweise")
                else -> t("teamManagement.notConfigured", "Nicht konfiguriert")
            },
            fontWeight = FontWeight.SemiBold,
        )
        st.missingItemLabels.forEach { Text("• $it", style = MaterialTheme.typography.caption) }
        if (st.complete) {
            Button(onClick = onFetch, enabled = !busy) {
                Text(t("teamManagement.manualFetch", "Daten abrufen"))
            }
        }
        OutlinedTextField(
            value = url,
            onValueChange = onUrl,
            label = { Text(t("teamManagement.myTischtennisUrlPlaceholder", "MyTT-Team-URL")) },
            modifier = Modifier.fillMaxWidth(),
            enabled = !busy,
        )
        Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
            TextButton(onClick = onParse, enabled = !busy && url.isNotBlank()) {
                Text(t("teamManagement.parseUrlAction", "URL prüfen"))
            }
        }
        Row(verticalAlignment = Alignment.CenterVertically) {
            androidx.compose.material.Switch(checked = createLeague, onCheckedChange = onCreateLeague)
            Text(t("mobile.teamMyTtCreateLeague", "Liga anlegen falls nötig"))
        }
        Row(verticalAlignment = Alignment.CenterVertically) {
            androidx.compose.material.Switch(checked = createSeason, onCheckedChange = onCreateSeason)
            Text(t("mobile.teamMyTtCreateSeason", "Saison anlegen falls nötig"))
        }
        Button(onClick = onConfigureTeam, enabled = !busy && url.isNotBlank()) {
            Text(t("mobile.teamMyTtLinkTeam", "Team verknüpfen"))
        }
        Spacer(Modifier.height(16.dp))
        Text(t("mobile.teamMyTtLeagueUrlTitle", "Tabellen-URL (Liga)"), fontWeight = FontWeight.Medium)
        OutlinedTextField(
            value = leagueUrl,
            onValueChange = onLeagueUrl,
            modifier = Modifier.fillMaxWidth(),
            enabled = !busy,
        )
        Row(verticalAlignment = Alignment.CenterVertically) {
            androidx.compose.material.Switch(checked = createSeasonLeague, onCheckedChange = onCreateSeasonLeague)
            Text(t("mobile.teamMyTtCreateSeasonLeague", "Saison anlegen (Liga)"))
        }
        Button(onClick = onConfigureLeague, enabled = !busy && leagueUrl.isNotBlank()) {
            Text(t("mobile.teamMyTtLinkLeague", "Liga verknüpfen"))
        }
        if (busy) CircularProgressIndicator()
    }
}
