package ru.durakscore.app

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlin.math.max
import kotlinx.coroutines.delay

const val STREAK_PRAISE_DURATION_MS = 30_000L

data class StreakPraiseResult(
    val playerId: String,
    val playerName: String,
    val streak: Int,
    val message: String
)

private val streakPraiseTemplates = listOf(
    "{name} держит {streak} без +1. Остальные, вы там карты держите или просто хуй в руке?",
    "У {nameGen} уже {streak}. Остальные выглядят так, будто правила впервые увидели пять минут назад.",
    "{name} снова без +1. Стол превращается в выставку коллективной рукожопости.",
    "Очко опять прошло мимо {nameGen}. Остальные, блядь, хоть вид сделайте, что сопротивляетесь.",
    "{name} держит {streak}. На фоне остальных это уже выглядит как игра взрослого с детсадом.",
    "У {nameGen} серия {streak}. Остальные уверенно работают поставщиками чужой красивой статистики.",
    "{name} опять сухой. Остальные за столом сегодня чисто мебель с картами.",
    "Серия {nameGen}: {streak}. У остальных, похоже, мозг ушёл на перекур и не вернулся.",
    "{name} снова мимо +1. Остальные позорятся настолько синхронно, что это уже командная работа.",
    "У {nameGen} {streak} без поражения. Остальным пора не карты менять, а руки целиком.",
    "{name} держится {streak}. Стол официально признан зоной массового обсёра.",
    "Очередная раздача — и снова не {nameDat}. Остальные, вы точно сюда играть пришли?",
    "{name} опять без +1. Пока остальные собирают очки, {name} собирает доказательства вашей беспомощности.",
    "У {nameGen} серия {streak}. Остальные выглядят как три ошибки, случайно севшие за один стол.",
    "{name} держит {streak}. Кто-нибудь объясните остальным, что проигрывать по очереди — не стратегия.",
    "Очко снова не досталось {nameDat}. Стол продолжает методично унижать всех остальных.",
    "{name} снова сухой. Остальные уже не соперники — обслуживающий персонал этой серии.",
    "Серия {streak} у {nameGen}. Чужая самооценка за столом сейчас где-то под плинтусом.",
    "{name} держится. Остальные будто соревнуются, кто быстрее обосрётся.",
    "У {nameGen} уже {streak}. Остальные могут продолжать изображать игру, если им так спокойнее.",
    "{name} снова без +1. Приложение уже не считает это везением — оно просто ржёт над остальными.",
    "Серия {nameGen}: {streak}. Остальные, сука, соберитесь хотя бы ради приличия.",
    "{name} опять проходит чистым. У остальных статистика выглядит как протокол аварии.",
    "Очко снова ушло не {nameDat}. Кто бы сомневался — цирк работает без выходных.",
    "{name} держит {streak}. Остальным пора признать: сегодня вы не игроки, вы контент.",
    "У {nameGen} серия {streak}. Стол уже напоминает персональную ферму чужих поражений.",
    "{name} снова сухой. Остальные так стабильно лажают, что это можно заносить в трудовую.",
    "Серия {streak} у {nameGen}. Остальным выдайте каски — по ним статистика уже ходит сапогами.",
    "{name} держится {streak}. Остальные выглядят так, будто каждый ход принимают решение монеткой.",
    "У {nameGen} всё ещё ноль новых проблем. У остальных — полный склад собственного пиздеца.",
    "{name} опять без +1. Остальные, вы там соревнуетесь за звание главного долбоёба вечера?",
    "Серия {nameGen}: {streak}. Кто-то за столом играет, остальные просто портят воздух.",
    "{name} держит {streak}. На фоне остальных это уже не серия, а публичная порка статистикой.",
    "Очко опять выбрало кого угодно, только не {nameAcc}. Остальные исправно несут свою службу позора.",
    "{name} снова сухой. Остальные так дружно тонут, что спасательный круг уже бесполезен.",
    "У {nameGen} серия {streak}. Если это ваши лучшие попытки, можно уже выключать свет.",
    "{name} держится. Остальные сегодня доказали, что дно действительно может быть командным.",
    "Серия {streak} у {nameGen}. У остальных руки есть, но по игре этого вообще не видно.",
    "{name} опять без +1. Стол выглядит как место, где один играет, а остальные отбывают наказание.",
    "У {nameGen} уже {streak}. Остальные, нахуй вы вообще сели, если собирались только страдать?",
    "{name} снова проходит сухим. Остальные продолжают жрать +1 как будто это бесплатная раздача.",
    "Серия {nameGen}: {streak}. У остальных уровень сопротивления — мокрый картон.",
    "{name} держит {streak}. Похоже, единственная ваша общая тактика — не мешать {nameDat} кайфовать.",
    "Очко снова не {nameDat}. Остальные, может, хоть правила перечитаете между унижениями?",
    "{name} опять без +1. Ваша коллективная беспомощность уже начинает выглядеть профессионально.",
    "У {nameGen} серия {streak}. Остальным пора открывать кружок «как стабильно обсираться за столом».",
    "{name} держится {streak}. Статистика остальных выглядит так, будто её заполнял враг.",
    "Серия {nameGen}: {streak}. Остальные сегодня не играют в дурака — они его рекламируют.",
    "{name} снова сухой. Остальные, блядь, хоть одного нормального хода за вечер родите.",
    "У {nameGen} уже {streak}. Стол официально переименован в филиал чужого унижения.",
    "{name} опять без +1. Остальные с такой игрой могут требовать зарплату за массовку.",
    "Серия {streak} у {nameGen}. Остальным пора перестать делать вид, что это всё ещё конкурентная игра.",
    "{name} держится. Чужие поражения уже складываются у {nameGen} в красивую коллекцию.",
    "У {nameGen} серия {streak}. Остальные выглядят как люди, которых сюда заманили обманом.",
    "{name} снова сухой. Ваша игра настолько херовая, что даже случайность стесняется вмешиваться.",
    "Очко опять прошло мимо {nameGen}. Остальные продолжают принимать весь пиздец на себя.",
    "{name} держит {streak}. Кто-нибудь вызовите остальным техподдержку — игроки явно не загрузились.",
    "Серия {nameGen}: {streak}. Остальные могут смело менять карты на таблички «я долбоёб».",
    "{name} снова без +1. Это уже не преимущество — это издевательство над вашими попытками играть.",
    "У {nameGen} уже {streak}. Остальные так уверенно сосут по статистике, будто тренировались.",
    "{name} держится {streak}. На столе четыре места, а ощущение, что соперников у {nameGen} нет вообще.",
    "Серия {streak} у {nameGen}. Остальные, может, пора перестать нажимать случайные кнопки в голове?",
    "{name} опять сухой. Чужая серия растёт быстрее, чем ваша способность сделать выводы.",
    "У {nameGen} серия {streak}. Стол уже не кипит — он смирился с вашей беспомощностью.",
    "{name} снова без +1. Остальные выглядят как неудачный эксперимент по командному позору.",
    "Очко опять не досталось {nameDat}. Да сколько можно так стабильно быть хуёвыми?",
    "{name} держит {streak}. Если бы за ошибки давали медали, остальные уже стояли бы на пьедестале.",
    "Серия {nameGen}: {streak}. Остальные уверенно превращают вечер в персональное шоу {nameGen}.",
    "{name} снова сухой. Все вокруг получают +1, будто подписали коллективный договор на унижение.",
    "У {nameGen} уже {streak}. Остальные могут дальше тасовать карты — навыки от этого не появятся.",
    "{name} держится. По ощущениям, остальные играют не против {nameGen}, а против собственного мозга.",
    "Серия {streak} у {nameGen}. Остальным пора признать поражение не в партии, а в профессии.",
    "{name} опять без +1. Такая массовая рукожопость уже заслуживает отдельной ачивки.",
    "У {nameGen} серия {streak}. Остальные, сука, вы хоть между раздачами анализируете, что творите?",
    "{name} держит {streak}. Стол продолжает выдавать остальным пощёчины, а они ещё и очередь занимают.",
    "Очко снова прошло мимо {nameGen}. Чужой позор уже работает на автомате.",
    "{name} снова сухой. Остальные сегодня играют роль статистов в фильме «Как просрать всё».",
    "Серия {nameGen}: {streak}. У остальных осталось два варианта: собраться или окончательно обосраться.",
    "{name} держится {streak}. Пока остальные ищут удачу, им бы сначала найти руки.",
    "У {nameGen} уже {streak}. Это уже не серия, это коллективное заявление остальных о профнепригодности.",
    "{name} опять без +1. Стол давно понял, кто тут играет, а кто просто занимает стулья.",
    "Серия {streak} у {nameGen}. Остальные продолжают доказывать, что предел тупого хода ещё не найден.",
    "{name} снова сухой. Если ваша цель была сделать {nameAcc} легендой — план выполняется идеально.",
    "У {nameGen} серия {streak}. Остальные с такой игрой скоро будут извиняться перед колодой.",
    "{name} держит {streak}. Чужие +1 уже выглядят как добровольные пожертвования в фонд {nameGen}.",
    "Очко опять не {nameDat}. Остальные, вы там специально по очереди подставляетесь?",
    "{name} снова без +1. Ваша общая стратегия выглядит как «авось кто-нибудь другой обосрётся сильнее».",
    "Серия {nameGen}: {streak}. Остальные уже не тонут — они обустраиваются на дне.",
    "{name} держится. Статистика остальных настолько убогая, что её хочется накрыть салфеткой.",
    "У {nameGen} уже {streak}. Если бы позор был валютой, остальные сегодня стали бы миллиардерами.",
    "{name} опять сухой. Остальные так долго лажают, что это уже можно считать традицией.",
    "Серия {streak} у {nameGen}. Колода, похоже, тоже потеряла уважение к остальным.",
    "{name} держит {streak}. На вашем месте я бы уже проверил, не перепутали ли вы игру с саморазрушением.",
    "У {nameGen} серия {streak}. Остальные продолжают героически проигрывать борьбу со здравым смыслом.",
    "{name} снова без +1. Стол смотрит на остальных и тихо охуевает от стабильности провала.",
    "Очко опять прошло мимо {nameGen}. Остальные настолько удобные соперники, что это уже подозрительно.",
    "{name} держится {streak}. Вы там не командой ли решили сделать одного человека неприкасаемым?",
    "Серия {nameGen}: {streak}. Остальным пора перестать искать оправдания — они уже закончились.",
    "{name} снова сухой. У остальных сегодня всё прекрасно, кроме рук, головы и результата.",
    "У {nameGen} уже {streak}. Стол официально сообщает: коллективный обсер продолжается."
)

fun isStreakPraiseMilestone(
    streak: Int
): Boolean {
    return streak in intArrayOf(
        5, 7, 9, 10, 12, 13, 15, 17, 20,
        25, 30, 35, 40, 45, 50
    ) ||
            (streak > 50 && streak % 5 == 0)
}


private data class RussianNameForms(
    val nominative: String,
    val genitive: String,
    val dative: String,
    val accusative: String,
    val instrumental: String
)

private fun russianNameForms(
    playerId: String,
    rawName: String
): RussianNameForms {

    /*
     * Для основной четвёрки задаём формы вручную —
     * тут склонения должны быть безошибочными.
     */
    return when (playerId.lowercase()) {
        "dmitry" ->
            RussianNameForms(
                nominative = "Дмитрий",
                genitive = "Дмитрия",
                dative = "Дмитрию",
                accusative = "Дмитрия",
                instrumental = "Дмитрием"
            )

        "denis" ->
            RussianNameForms(
                nominative = "Денис",
                genitive = "Дениса",
                dative = "Денису",
                accusative = "Дениса",
                instrumental = "Денисом"
            )

        "rybka" ->
            RussianNameForms(
                nominative = "Рыбка",
                genitive = "Рыбки",
                dative = "Рыбке",
                accusative = "Рыбку",
                instrumental = "Рыбкой"
            )

        "masha" ->
            RussianNameForms(
                nominative = "Маша",
                genitive = "Маши",
                dative = "Маше",
                accusative = "Машу",
                instrumental = "Машей"
            )

        else ->
            guessRussianNameForms(
                rawName
            )
    }
}

private fun guessRussianNameForms(
    rawName: String
): RussianNameForms {

    val name =
        rawName.trim()

    if (name.isBlank()) {
        return RussianNameForms(
            nominative = rawName,
            genitive = rawName,
            dative = rawName,
            accusative = rawName,
            instrumental = rawName
        )
    }

    val lower =
        name.lowercase()

    return when {
        lower.endsWith("ий") -> {
            val stem =
                name.dropLast(2)

            RussianNameForms(
                nominative = name,
                genitive = stem + "ия",
                dative = stem + "ию",
                accusative = stem + "ия",
                instrumental = stem + "ием"
            )
        }

        lower.endsWith("й") -> {
            val stem =
                name.dropLast(1)

            RussianNameForms(
                nominative = name,
                genitive = stem + "я",
                dative = stem + "ю",
                accusative = stem + "я",
                instrumental = stem + "ем"
            )
        }

        lower.endsWith("а") -> {
            val stem =
                name.dropLast(1)

            val genitiveEnding =
                if (
                    stem.lastOrNull()
                        ?.lowercaseChar() in
                    listOf(
                        'г', 'к', 'х',
                        'ж', 'ч', 'ш', 'щ'
                    )
                ) {
                    "и"
                } else {
                    "ы"
                }

            RussianNameForms(
                nominative = name,
                genitive = stem + genitiveEnding,
                dative = stem + "е",
                accusative = stem + "у",
                instrumental = stem + "ой"
            )
        }

        lower.endsWith("я") -> {
            val stem =
                name.dropLast(1)

            RussianNameForms(
                nominative = name,
                genitive = stem + "и",
                dative = stem + "е",
                accusative = stem + "ю",
                instrumental = stem + "ей"
            )
        }

        lower.lastOrNull() in
                ('а'..'я') &&
                lower.lastOrNull() !in
                listOf(
                    'ь', 'й'
                ) -> {

            RussianNameForms(
                nominative = name,
                genitive = name + "а",
                dative = name + "у",
                accusative = name + "а",
                instrumental = name + "ом"
            )
        }

        else -> {
            /*
             * Нестандартные/иностранные имена не ломаем:
             * оставляем как ввёл пользователь.
             */
            RussianNameForms(
                nominative = name,
                genitive = name,
                dative = name,
                accusative = name,
                instrumental = name
            )
        }
    }
}

private fun stableHash(
    value: String
): Long {

    var hash =
        -3750763034362895579L

    value.forEach { char ->
        hash =
            hash xor char.code.toLong()

        hash *=
            1099511628211L
    }

    return hash
}

private fun positiveIndex(
    value: Long,
    size: Int
): Int {

    val mod =
        value % size.toLong()

    return if (mod < 0L) {
        (mod + size).toInt()
    } else {
        mod.toInt()
    }
}

private fun phraseIndexFor(
    playerId: String,
    streak: Int,
    historySize: Int
): Int {

    /*
     * Один общий пул из 100 жёстких фраз доступен уже с СЕРИИ 5.
     *
     * Выбор псевдослучайный, но детерминированный по событию:
     * одинаковая история покажет одинаковую фразу на всех телефонах,
     * а разные игроки/серии/раздачи будут реально крутить весь пул.
     */
    val runStart =
        historySize - streak

    val seed =
        stableHash(
            "$playerId|$runStart|$streak|$historySize|streak-praise-v5"
        )

    var index =
        positiveIndex(
            seed,
            streakPraiseTemplates.size
        )

    /*
     * Защита от редкого повтора соседней отметки той же серии.
     */
    val previousMilestone =
        when (streak) {
            7 -> 5
            9 -> 7
            10 -> 9
            12 -> 10
            13 -> 12
            15 -> 13
            17 -> 15
            20 -> 17
            25 -> 20
            30 -> 25
            35 -> 30
            40 -> 35
            45 -> 40
            50 -> 45
            else ->
                if (
                    streak > 50 &&
                    streak % 5 == 0
                ) {
                    streak - 5
                } else {
                    null
                }
        }

    if (previousMilestone != null) {
        val previousHistorySize =
            historySize -
                    (streak - previousMilestone)

        val previousRunStart =
            previousHistorySize -
                    previousMilestone

        val previousSeed =
            stableHash(
                "$playerId|$previousRunStart|$previousMilestone|$previousHistorySize|streak-praise-v5"
            )

        val previousIndex =
            positiveIndex(
                previousSeed,
                streakPraiseTemplates.size
            )

        if (index == previousIndex) {
            index =
                (index + 37) %
                        streakPraiseTemplates.size
        }
    }

    return index
}

fun buildStreakPraises(
    players: List<Pair<String, String>>,
    history: List<String>
): List<StreakPraiseResult> {

    if (players.isEmpty() || history.isEmpty()) {
        return emptyList()
    }

    val lastLoserId =
        history.last()

    val candidates =
        players.mapNotNull { (playerId, playerName) ->

            if (playerId == lastLoserId) {
                return@mapNotNull null
            }

            var streak = 0

            for (loserId in history.asReversed()) {
                if (loserId == playerId) {
                    break
                }

                streak++
            }

            if (!isStreakPraiseMilestone(streak)) {
                return@mapNotNull null
            }

            Triple(
                playerId,
                playerName,
                streak
            )
        }
            .sortedWith(
                compareByDescending<Triple<String, String, Int>> {
                    it.third
                }.thenBy {
                    it.first
                }
            )

    return candidates.map { chosen ->

        val playerId =
            chosen.first

        val playerName =
            chosen.second

        val streak =
            chosen.third

        val phraseIndex =
            phraseIndexFor(
                playerId = playerId,
                streak = streak,
                historySize = history.size
            )

        val nameForms =
            russianNameForms(
                playerId = playerId,
                rawName = playerName
            )

        val message =
            streakPraiseTemplates[
                phraseIndex
            ]
                .replace(
                    "{nameGen}",
                    nameForms.genitive
                )
                .replace(
                    "{nameDat}",
                    nameForms.dative
                )
                .replace(
                    "{nameAcc}",
                    nameForms.accusative
                )
                .replace(
                    "{nameIns}",
                    nameForms.instrumental
                )
                .replace(
                    "{name}",
                    nameForms.nominative
                )
                .replace(
                    "{streak}",
                    streak.toString()
                )

        StreakPraiseResult(
            playerId = playerId,
            playerName = playerName,
            streak = streak,
            message = message
        )
    }
}

/*
 * Оставляем старую функцию для совместимости.
 */
fun buildStreakPraise(
    players: List<Pair<String, String>>,
    history: List<String>
): StreakPraiseResult? =
    buildStreakPraises(
        players = players,
        history = history
    ).firstOrNull()

@Composable
fun QueuedStreakPraiseBanner(
    gameKey: String,
    players: List<Pair<String, String>>,
    history: List<String>,
    includeLatestOnStart: Boolean = false,
    topSpacingDp: Int = 12
) {

    /*
     * НОВАЯ ЛОГИКА:
     *
     * Никакой очереди по 30 секунд.
     *
     * Если на одном ходе milestone получили сразу несколько игроков,
     * показываем их ОДНОВРЕМЕННО в одном компактном блоке.
     *
     * Если во время показа прилетел новый milestone —
     * старый блок сразу заменяется новым.
     *
     * В результате игра никогда не ждёт баннеры.
     */
    var activePraises by remember(gameKey) {
        mutableStateOf<List<StreakPraiseResult>>(
            emptyList()
        )
    }

    var activeEventHistorySize by remember(gameKey) {
        mutableIntStateOf(-1)
    }

    var lastProcessedHistorySize by remember(
        gameKey,
        includeLatestOnStart
    ) {
        mutableIntStateOf(
            if (
                includeLatestOnStart &&
                history.isNotEmpty()
            ) {
                history.size - 1
            } else {
                history.size
            }
        )
    }

    LaunchedEffect(
        gameKey,
        history.size
    ) {

        if (
            history.size <
            lastProcessedHistorySize
        ) {
            activePraises =
                emptyList()

            activeEventHistorySize =
                -1

            lastProcessedHistorySize =
                history.size

            return@LaunchedEffect
        }

        if (
            history.size ==
            lastProcessedHistorySize
        ) {
            return@LaunchedEffect
        }

        /*
         * Если во время показа серии игрок получает +1,
         * его серия закончилась прямо сейчас — убираем его баннер
         * немедленно, а не ждём окончания 30-секундного таймера.
         *
         * Берём ВСЕ новые раздачи, потому что Firestore иногда может
         * прислать сразу несколько изменений одним обновлением.
         */
        val newLoserIds =
            history
                .subList(
                    lastProcessedHistorySize
                        .coerceAtLeast(0),
                    history.size
                )
                .toSet()

        if (
            activePraises.any { praise ->
                praise.playerId in newLoserIds
            }
        ) {
            activePraises =
                activePraises.filterNot { praise ->
                    praise.playerId in newLoserIds
                }

            if (activePraises.isEmpty()) {
                activeEventHistorySize =
                    -1
            }
        }

        val fromSize =
            (lastProcessedHistorySize + 1)
                .coerceAtLeast(1)

        var latestPraises =
            emptyList<StreakPraiseResult>()

        var latestPrefixSize =
            -1

        /*
         * Если Firestore прислал сразу несколько новых ходов,
         * не заставляем пользователя смотреть старые события.
         * Берём самое СВЕЖЕЕ событие стрика.
         */
        for (
        prefixSize in
        fromSize..history.size
        ) {

            val praises =
                buildStreakPraises(
                    players =
                        players,
                    history =
                        history.take(
                            prefixSize
                        )
                )

            if (
                praises.isNotEmpty()
            ) {
                latestPraises =
                    praises

                latestPrefixSize =
                    prefixSize
            }
        }

        /*
         * Если milestone случился внутри пачки обновлений, но после него
         * этот же игрок успел получить +1, не показываем уже мёртвую серию.
         */
        if (
            latestPraises.isNotEmpty() &&
            latestPrefixSize >= 0 &&
            latestPrefixSize < history.size
        ) {
            val losersAfterMilestone =
                history
                    .drop(latestPrefixSize)
                    .toSet()

            latestPraises =
                latestPraises.filterNot { praise ->
                    praise.playerId in losersAfterMilestone
                }
        }

        lastProcessedHistorySize =
            history.size

        if (
            latestPraises.isNotEmpty()
        ) {
            activePraises =
                latestPraises

            activeEventHistorySize =
                latestPrefixSize
        }
    }

    LaunchedEffect(
        gameKey,
        activeEventHistorySize
    ) {

        if (
            activeEventHistorySize <
            0 ||
            activePraises.isEmpty()
        ) {
            return@LaunchedEffect
        }

        val eventId =
            activeEventHistorySize

        delay(
            STREAK_PRAISE_DURATION_MS
        )

        if (
            activeEventHistorySize ==
            eventId
        ) {
            activePraises =
                emptyList()

            activeEventHistorySize =
                -1
        }
    }

    /*
     * ВАЖНО:
     * streak-плашка больше не участвует в layout игрового стола.
     * Popup рисуется поверх неинтерактивной верхней части экрана,
     * поэтому появление/исчезновение плашки не двигает карточки
     * игроков и кнопки +1 — миссклика из-за сдвига больше нет.
     */
    if (
        activePraises.isNotEmpty()
    ) {

        Popup(
            alignment =
                Alignment.TopCenter,
            properties =
                PopupProperties(
                    focusable = false
                )
        ) {

            Box(
                modifier =
                    Modifier
                        .fillMaxWidth()
                        .padding(
                            top =
                                (20 + topSpacingDp).dp,
                            start =
                                14.dp,
                            end =
                                14.dp
                        )
            ) {

                if (
                    activePraises.size ==
                    1
                ) {

                    StreakPraiseBanner(
                        praise =
                            activePraises.first()
                    )

                } else {

                    MultiStreakPraiseBanner(
                        praises =
                            activePraises,
                        lastLoserName =
                            history
                                .lastOrNull()
                                ?.let { loserId ->
                                    players
                                        .firstOrNull {
                                            it.first ==
                                                    loserId
                                        }
                                        ?.second
                                }
                    )
                }
            }
        }
    }
}

@Composable
private fun MultiStreakPraiseBanner(
    praises: List<StreakPraiseResult>,
    lastLoserName: String?
) {

    PokerPanel {

        Text(
            text =
                "🔥  СЕРИИ СРАЗУ У ${praises.size}",
            color =
                PokerPalette.Gold,
            fontSize =
                15.sp,
            fontWeight =
                FontWeight.Bold
        )

        Spacer(
            modifier =
                androidx.compose.ui.Modifier.height(
                    7.dp
                )
        )

        praises.forEach { praise ->

            Text(
                text =
                    "${praise.playerName} — ${praise.streak} без +1",
                color =
                    PokerPalette.TextPrimary,
                fontSize =
                    16.sp,
                fontWeight =
                    FontWeight.SemiBold
            )

            Spacer(
                modifier =
                    androidx.compose.ui.Modifier.height(
                        3.dp
                    )
            )
        }

        Spacer(
            modifier =
                androidx.compose.ui.Modifier.height(
                    6.dp
                )
        )

        val joke =
            when {

                lastLoserName != null &&
                        praises.size >= 3 ->
                    "$lastLoserName, ты там один очки собираешь, что ли?"

                lastLoserName != null ->
                    "$lastLoserName, у людей серии растут. У тебя пока растёт только счёт."

                else ->
                    "За столом массовая неприкосновенность. Кто-то явно работает поставщиком +1."
            }

        Text(
            text =
                joke,
            color =
                PokerPalette.Gold,
            fontSize =
                15.sp,
            fontWeight =
                FontWeight.SemiBold
        )
    }
}

@Composable
fun StreakPraiseBanner(
    praise: StreakPraiseResult
) {
    PokerPanel {
        Text(
            text = "🔥  СЕРИЯ ${praise.streak}",
            color = PokerPalette.Gold,
            fontSize = 15.sp,
            fontWeight = FontWeight.Bold
        )

        Spacer(
            modifier =
                androidx.compose.ui.Modifier.height(7.dp)
        )

        Text(
            text = praise.message,
            color = PokerPalette.TextPrimary,
            fontSize = 17.sp,
            fontWeight = FontWeight.SemiBold
        )
    }
}