package de.tsschulz.tt_tagebuch.app.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.layout.Arrangement
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.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Divider
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.shared.api.models.AddMiniChampionshipBody
import de.tsschulz.tt_tagebuch.shared.api.models.AddStandardTournamentBody
import de.tsschulz.tt_tagebuch.shared.api.models.InternalTournamentSummaryDto
import de.tsschulz.tt_tagebuch.shared.api.models.OfficialParticipationEntryDto
import de.tsschulz.tt_tagebuch.shared.api.models.canReadTournaments
import de.tsschulz.tt_tagebuch.shared.api.models.canWriteTournaments
import de.tsschulz.tt_tagebuch.shared.i18n.MobileStrings
import de.tsschulz.tt_tagebuch.shared.state.ClubTournamentDisplayFilter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Calendar

private data class ParticipationFlatRow(
    val tournamentId: String?,
    val tournamentTitle: String?,
    val entry: OfficialParticipationEntryDto,
)

private val TournamentsPad = 20.dp
private val TournamentsTouchMin = 48.dp

private sealed class TournamentsMainRoute {
    data object Browse : TournamentsMainRoute()
    data class Editor(val tournamentId: Int) : TournamentsMainRoute()
    data object CreateStandard : TournamentsMainRoute()
    data object CreateMini : TournamentsMainRoute()
    data object OfficialWorkspace : TournamentsMainRoute()
}

@Composable
internal fun TournamentsScreen(dependencies: AppDependencies) {
    val languageCode = LocalLanguageCode.current
    fun tr(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    val clubState by dependencies.clubManager.state.collectAsState()
    val clubId = clubState.currentClubId ?: return
    val perms = clubState.currentPermissions
    val internalState by dependencies.clubInternalTournamentsManager.state.collectAsState()
    val officialState by dependencies.officialTournamentsReadManager.state.collectAsState()
    var searchQuery by rememberSaveable { mutableStateOf("") }
    var showInternalStats by remember { mutableStateOf(false) }
    var mainRoute by remember { mutableStateOf<TournamentsMainRoute>(TournamentsMainRoute.Browse) }

    if (perms?.canReadTournaments() != true) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(TournamentsPad),
        ) {
            Text(tr("mobile.noTournamentAccess", "Keine Berechtigung für Turniere."))
        }
        return
    }

    LaunchedEffect(clubId, internalState.filter) {
        dependencies.clubInternalTournamentsManager.loadList(clubId)
    }

    LaunchedEffect(clubId) {
        dependencies.officialTournamentsReadManager.load(clubId)
    }

    val participationFlatRows = remember(officialState.participationBuckets) {
        officialState.participationBuckets.flatMap { bucket ->
            bucket.entries.map { entry ->
                ParticipationFlatRow(bucket.tournamentId, bucket.title, entry)
            }
        }
    }

    val modeDescription = when (internalState.filter) {
        ClubTournamentDisplayFilter.Mini -> tr("tournaments.miniChampionships", "Mini")
        ClubTournamentDisplayFilter.External -> tr("tournaments.openTournaments", "Offen")
        ClubTournamentDisplayFilter.Internal -> tr("tournaments.internalTournaments", "Vereins-Turniere")
    }

    val sortedInternal = remember(internalState.tournaments) {
        internalState.tournaments.sortedByDescending { it.date ?: "" }
    }

    val filteredInternal = remember(sortedInternal, searchQuery) {
        val q = searchQuery.trim().lowercase()
        if (q.isEmpty()) sortedInternal
        else {
            sortedInternal.filter { t ->
                val name = (t.name ?: "").lowercase()
                val date = (t.date ?: "").lowercase()
                name.contains(q) || date.contains(q)
            }
        }
    }

    val countLabel = remember(filteredInternal.size, sortedInternal.size, languageCode) {
        tr("tournaments.showingTournamentCount", "{visible} von {total}")
            .replace("{visible}", filteredInternal.size.toString())
            .replace("{total}", sortedInternal.size.toString())
    }

    if (showInternalStats) {
        InternalTournamentStatsDialog(
            clubId = clubId,
            dependencies = dependencies,
            onDismiss = { showInternalStats = false },
        )
    }

    when (val route = mainRoute) {
        TournamentsMainRoute.Browse -> {
            LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(horizontal = TournamentsPad, vertical = 16.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        item {
            Text(
                tr("navigation.clubTournaments", "Turniere"),
                style = MaterialTheme.typography.h5,
                fontWeight = FontWeight.SemiBold,
            )
            Text(
                tr("mobile.tournamentsHubHint", "Vereins-Turniere, importierte Meldelisten und Teilnahmen – hier in der App."),
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.72f),
                modifier = Modifier.padding(top = 4.dp, bottom = 8.dp),
            )
        }

        item {
            OutlinedButton(
                onClick = { mainRoute = TournamentsMainRoute.OfficialWorkspace },
                modifier = Modifier.fillMaxWidth(),
            ) {
                Text(tr("officialTournaments.openWorkspace", "Offizielle Turniere & Teilnahmen …"))
            }
        }

        item {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .horizontalScroll(rememberScrollState()),
                horizontalArrangement = Arrangement.spacedBy(8.dp),
            ) {
                TournamentModePill(
                    label = "🏆 " + tr("tournaments.internalTournaments", "Interne Turniere"),
                    selected = internalState.filter == ClubTournamentDisplayFilter.Internal,
                    onClick = {
                        dependencies.clubInternalTournamentsManager.setFilter(ClubTournamentDisplayFilter.Internal)
                    },
                )
                TournamentModePill(
                    label = "🌐 " + tr("tournaments.openTournaments", "Offene Turniere"),
                    selected = internalState.filter == ClubTournamentDisplayFilter.External,
                    onClick = {
                        dependencies.clubInternalTournamentsManager.setFilter(ClubTournamentDisplayFilter.External)
                    },
                )
                TournamentModePill(
                    label = "🏅 " + tr("tournaments.miniChampionships", "Minimeisterschaften"),
                    selected = internalState.filter == ClubTournamentDisplayFilter.Mini,
                    onClick = {
                        dependencies.clubInternalTournamentsManager.setFilter(ClubTournamentDisplayFilter.Mini)
                    },
                )
            }
        }

        item {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp),
            ) {
                Text(
                    modeDescription,
                    style = MaterialTheme.typography.body2,
                    color = MaterialTheme.colors.onSurface.copy(alpha = 0.85f),
                    modifier = Modifier.weight(1f),
                )
                if (internalState.filter == ClubTournamentDisplayFilter.Internal) {
                    TextButton(onClick = { showInternalStats = true }) {
                        Text(
                            "📊 " + tr("tournaments.internalStatsOpenButton", "Turnierstatistik (Einzel)"),
                            style = MaterialTheme.typography.caption,
                            fontWeight = FontWeight.SemiBold,
                        )
                    }
                }
            }
        }

        item {
            OutlinedTextField(
                value = searchQuery,
                onValueChange = { searchQuery = it },
                modifier = Modifier.fillMaxWidth(),
                singleLine = true,
                label = { Text(tr("tournaments.tournamentName", "Turniername")) },
                placeholder = { Text(tr("tournaments.tournamentName", "Turniername")) },
            )
            Text(
                countLabel,
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.65f),
                modifier = Modifier.padding(top = 4.dp),
            )
        }

        item {
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
                if (internalState.filter == ClubTournamentDisplayFilter.Mini) {
                    OutlinedButton(onClick = { mainRoute = TournamentsMainRoute.CreateMini }) {
                        Text(tr("tournaments.miniChampionships", "Minimeisterschaft") + " +")
                    }
                } else {
                    OutlinedButton(onClick = { mainRoute = TournamentsMainRoute.CreateStandard }) {
                        Text(tr("tournaments.newTournament", "Neues Turnier"))
                    }
                }
            }
        }

        if (internalState.isLoadingList) {
            item { CircularProgressIndicator(modifier = Modifier.padding(vertical = 16.dp)) }
        } else {
            internalState.error?.let { err ->
                item {
                    Text(err, color = MaterialTheme.colors.error)
                }
            }
            if (sortedInternal.isEmpty()) {
                item {
                    Text(
                        tr("mobile.noClubTournaments", "Keine Turniere in dieser Ansicht."),
                        style = MaterialTheme.typography.body2,
                        modifier = Modifier.padding(vertical = 8.dp),
                    )
                }
            } else if (filteredInternal.isEmpty()) {
                item {
                    Column(modifier = Modifier.padding(vertical = 12.dp)) {
                        Text(
                            tr("tournaments.noMatchingTournamentsTitle", "Keine passenden Turniere"),
                            fontWeight = FontWeight.SemiBold,
                        )
                        Text(
                            tr("tournaments.adjustTournamentSearch", "Suchbegriff anpassen."),
                            style = MaterialTheme.typography.body2,
                            color = MaterialTheme.colors.onSurface.copy(alpha = 0.75f),
                            modifier = Modifier.padding(top = 4.dp),
                        )
                    }
                }
            } else {
                itemsIndexed(
                    filteredInternal,
                    key = { _, t -> t.id.toString() },
                ) { _, t ->
                    InternalTournamentListCard(
                        tournament = t,
                        selected = false,
                        unknownDateLabel = tr("tournaments.unknownDate", "Datum unbekannt"),
                        onClick = { mainRoute = TournamentsMainRoute.Editor(t.id) },
                    )
                }
            }
        }

        item {
            Spacer(modifier = Modifier.height(16.dp))
            Text(tr("officialTournaments.savedEvents", "Offizielle Turniere (Import)"), fontWeight = FontWeight.SemiBold)
        }

        if (officialState.isLoading) {
            item { CircularProgressIndicator(modifier = Modifier.padding(vertical = 8.dp)) }
        } else {
            officialState.error?.let { err ->
                item { Text(err, color = MaterialTheme.colors.error) }
            }
            if (officialState.tournaments.isEmpty()) {
                item {
                    Text(
                        tr("officialTournaments.noEvents", "Keine importierten Turniere."),
                        style = MaterialTheme.typography.body2,
                    )
                }
            } else {
                itemsIndexed(
                    officialState.tournaments,
                    key = { index, ot -> "${ot.id}-$index" },
                ) { _, ot ->
                    Column(modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)) {
                        Text(ot.title ?: "Turnier #${ot.id}", fontWeight = FontWeight.Medium)
                        ot.eventDate?.takeIf { it.isNotBlank() }?.let {
                            Text(it, style = MaterialTheme.typography.caption)
                        }
                    }
                    Divider()
                }
            }
        }

        item {
            Spacer(modifier = Modifier.height(12.dp))
            Text(tr("officialTournaments.participations", "Teilnahmen (übersicht)"), fontWeight = FontWeight.SemiBold)
        }

        if (participationFlatRows.isEmpty() && !officialState.isLoading) {
            item {
                Text(
                    tr("mobile.noOfficialParticipations", "Keine erfassten Teilnahmen."),
                    style = MaterialTheme.typography.body2,
                )
            }
        } else {
            itemsIndexed(
                participationFlatRows,
                key = { index, _ -> "participation-$index" },
            ) { _, r ->
                ParticipationRow(tournamentTitle = r.tournamentTitle, entry = r.entry)
            }
        }

        item {
            Spacer(modifier = Modifier.height(20.dp))
            Text(
                tr("mobile.tournamentsWebHintFooter", "Offizielle Meldelisten und Teilnahmen unten; Vereins-Turniere oben in der App bearbeitbar."),
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.62f),
            )
        }
            }
        }
        is TournamentsMainRoute.Editor -> InternalTournamentEditorScreen(
            clubId = clubId,
            tournamentId = route.tournamentId,
            dependencies = dependencies,
            onClose = {
                mainRoute = TournamentsMainRoute.Browse
                dependencies.applicationScope.launch {
                    dependencies.clubInternalTournamentsManager.loadList(clubId)
                }
            },
        )
        TournamentsMainRoute.CreateStandard -> TournamentCreateStandardScreen(
            clubId = clubId,
            allowsExternal = internalState.filter == ClubTournamentDisplayFilter.External,
            dependencies = dependencies,
            tr = ::tr,
            onBack = { mainRoute = TournamentsMainRoute.Browse },
            onCreated = { newId: Int ->
                mainRoute = TournamentsMainRoute.Editor(newId)
                dependencies.applicationScope.launch {
                    dependencies.clubInternalTournamentsManager.loadList(clubId)
                }
            },
        )
        TournamentsMainRoute.CreateMini -> TournamentCreateMiniScreen(
            clubId = clubId,
            dependencies = dependencies,
            tr = ::tr,
            onBack = { mainRoute = TournamentsMainRoute.Browse },
            onCreated = { newId: Int ->
                mainRoute = TournamentsMainRoute.Editor(newId)
                dependencies.applicationScope.launch {
                    dependencies.clubInternalTournamentsManager.loadList(clubId)
                }
            },
        )
        TournamentsMainRoute.OfficialWorkspace -> OfficialTournamentsWorkspaceScreen(
            clubId = clubId,
            canWrite = perms?.canWriteTournaments() == true,
            dependencies = dependencies,
            tr = ::tr,
            onClose = {
                mainRoute = TournamentsMainRoute.Browse
                dependencies.applicationScope.launch {
                    dependencies.officialTournamentsReadManager.load(clubId)
                }
            },
        )
    }
}

@Composable
private fun TournamentCreateStandardScreen(
    clubId: Int,
    allowsExternal: Boolean,
    dependencies: AppDependencies,
    tr: (String, String) -> String,
    onBack: () -> Unit,
    onCreated: (Int) -> Unit,
) {
    var name by remember { mutableStateOf("") }
    var date by rememberSaveable { mutableStateOf(todayIsoDate()) }
    var ws by remember { mutableStateOf("3") }
    var error by remember { mutableStateOf<String?>(null) }
    var busy by remember { mutableStateOf(false) }
    val scroll = rememberScrollState()
    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(scroll)
            .padding(horizontal = TournamentsPad, vertical = 16.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        TextButton(onClick = onBack) { Text(tr("mobile.back", "Zurück")) }
        Text(
            tr("tournaments.newTournament", "Neues Turnier"),
            style = MaterialTheme.typography.h6,
            fontWeight = FontWeight.SemiBold,
        )
        error?.let { Text(it, color = MaterialTheme.colors.error) }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text(tr("tournaments.tournamentName", "Turniername")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
        )
        LocalizedDatePickerField(
            value = date,
            onValueChange = { date = it },
            label = tr("tournaments.date", "Datum"),
            modifier = Modifier.fillMaxWidth(),
        )
        OutlinedTextField(
            value = ws,
            onValueChange = { ws = it.filter { ch -> ch.isDigit() }.take(2) },
            label = { Text(tr("tournaments.winningSets", "Gewinnsätze")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
        )
        Button(
            onClick = {
                if (date.isBlank()) {
                    error = tr("tournaments.pleaseEnterDate", "Bitte Datum eingeben")
                    return@Button
                }
                busy = true
                error = null
                dependencies.applicationScope.launch {
                    runCatching {
                        val res = withContext(Dispatchers.IO) {
                            dependencies.tournamentsApi.addStandardTournament(
                                AddStandardTournamentBody(
                                    clubId = clubId,
                                    tournamentName = name.trim().ifBlank { date.trim() },
                                    date = date.trim(),
                                    winningSets = ws.toIntOrNull() ?: 3,
                                    allowsExternal = allowsExternal,
                                    isDoublesTournament = false,
                                ),
                            )
                        }
                        onCreated(res.id)
                    }.onFailure { error = it.message }
                    busy = false
                }
            },
            enabled = !busy,
            modifier = Modifier.fillMaxWidth(),
        ) {
            Text(if (busy) "…" else tr("common.create", "Erstellen"))
        }
    }
}

@Composable
private fun TournamentCreateMiniScreen(
    clubId: Int,
    dependencies: AppDependencies,
    tr: (String, String) -> String,
    onBack: () -> Unit,
    onCreated: (Int) -> Unit,
) {
    var ort by remember { mutableStateOf("") }
    var date by rememberSaveable { mutableStateOf(todayIsoDate()) }
    var year by remember { mutableStateOf(Calendar.getInstance().get(Calendar.YEAR).toString()) }
    var ws by remember { mutableStateOf("1") }
    var error by remember { mutableStateOf<String?>(null) }
    var busy by remember { mutableStateOf(false) }
    val scroll = rememberScrollState()
    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(scroll)
            .padding(horizontal = TournamentsPad, vertical = 16.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        TextButton(onClick = onBack) { Text(tr("mobile.back", "Zurück")) }
        Text(
            tr("tournaments.miniChampionships", "Minimeisterschaft"),
            style = MaterialTheme.typography.h6,
            fontWeight = FontWeight.SemiBold,
        )
        error?.let { Text(it, color = MaterialTheme.colors.error) }
        OutlinedTextField(
            value = ort,
            onValueChange = { ort = it },
            label = { Text(tr("tournaments.miniChampionshipLocation", "Ort")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
        )
        LocalizedDatePickerField(
            value = date,
            onValueChange = { date = it },
            label = tr("tournaments.date", "Datum"),
            modifier = Modifier.fillMaxWidth(),
        )
        OutlinedTextField(
            value = year,
            onValueChange = { year = it.filter { ch -> ch.isDigit() }.take(4) },
            label = { Text(tr("tournaments.miniChampionshipYear", "Jahr")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
        )
        OutlinedTextField(
            value = ws,
            onValueChange = { ws = it.filter { ch -> ch.isDigit() }.take(1) },
            label = { Text(tr("tournaments.winningSets", "Gewinnsätze")) },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
        )
        Button(
            onClick = {
                if (ort.isBlank() || date.isBlank()) {
                    error = tr("tournaments.enterMiniLocation", "Ort und Datum eingeben")
                    return@Button
                }
                val y = year.toIntOrNull() ?: 0
                if (y < 2000 || y > 2100) {
                    error = tr("tournaments.miniChampionshipYearHint", "Jahr ungültig")
                    return@Button
                }
                busy = true
                error = null
                dependencies.applicationScope.launch {
                    runCatching {
                        val res = withContext(Dispatchers.IO) {
                            dependencies.tournamentsApi.addMiniChampionship(
                                AddMiniChampionshipBody(
                                    clubId = clubId,
                                    ort = ort.trim(),
                                    date = date.trim(),
                                    year = y,
                                    winningSets = ws.toIntOrNull() ?: 1,
                                ),
                            )
                        }
                        onCreated(res.id)
                    }.onFailure { error = it.message }
                    busy = false
                }
            },
            enabled = !busy,
            modifier = Modifier.fillMaxWidth(),
        ) {
            Text(if (busy) "…" else tr("common.create", "Erstellen"))
        }
    }
}

@Composable
private fun TournamentModePill(
    label: String,
    selected: Boolean,
    onClick: () -> Unit,
) {
    val shape = RoundedCornerShape(999.dp)
    val bg = if (selected) {
        MaterialTheme.colors.primary.copy(alpha = 0.14f)
    } else {
        MaterialTheme.colors.surface
    }
    val borderColor = if (selected) {
        MaterialTheme.colors.primary
    } else {
        MaterialTheme.colors.onSurface.copy(alpha = 0.12f)
    }
    TextButton(
        onClick = onClick,
        modifier = Modifier
            .heightIn(min = 40.dp)
            .clip(shape)
            .background(bg)
            .border(width = if (selected) 2.dp else 1.dp, color = borderColor, shape = shape),
    ) {
        Text(
            label,
            fontWeight = if (selected) FontWeight.Bold else FontWeight.Medium,
        )
    }
}

@Composable
private fun InternalTournamentListCard(
    tournament: InternalTournamentSummaryDto,
    selected: Boolean,
    unknownDateLabel: String,
    onClick: () -> Unit,
) {
    val shape = RoundedCornerShape(14.dp)
    val borderColor = if (selected) {
        MaterialTheme.colors.primary
    } else {
        MaterialTheme.colors.onSurface.copy(alpha = 0.15f)
    }
    val bg = if (selected) {
        MaterialTheme.colors.primary.copy(alpha = 0.08f)
    } else {
        MaterialTheme.colors.surface
    }
    val dateLine = tournament.date?.takeIf { it.isNotBlank() } ?: unknownDateLabel
    Surface(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp)
            .clip(shape)
            .border(
                width = if (selected) 2.dp else 1.dp,
                color = borderColor,
                shape = shape,
            )
            .clickable(onClick = onClick),
        color = bg,
        elevation = if (selected) 4.dp else 1.dp,
        shape = shape,
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .heightIn(min = TournamentsTouchMin)
                .padding(horizontal = 16.dp, vertical = 14.dp),
        ) {
            Text(
                tournament.name ?: "Turnier #${tournament.id}",
                fontWeight = FontWeight.SemiBold,
                style = MaterialTheme.typography.subtitle1,
            )
            Text(
                dateLine,
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.72f),
            )
        }
    }
}

@Composable
private fun ParticipationRow(tournamentTitle: String?, entry: OfficialParticipationEntryDto) {
    Column(modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp)) {
        Text(
            listOfNotNull(entry.memberName, tournamentTitle).joinToString(" · "),
            style = MaterialTheme.typography.body2,
            fontWeight = FontWeight.Medium,
        )
        Text(
            listOfNotNull(entry.competitionName, entry.date, entry.placement?.let { p -> "Pl. $p" })
                .filter { it.isNotBlank() }
                .joinToString(" · "),
            style = MaterialTheme.typography.caption,
            color = MaterialTheme.colors.onSurface.copy(alpha = 0.75f),
        )
    }
    Divider()
}
