package ru.durakscore.app

import java.util.Date

enum class GameActionType {
    ADD_POINT,
    UNDO_LAST
}

data class QueuedGameAction(
    val type: GameActionType,
    val playerId: String? = null
)

data class LoadedGame(
    val id: String,
    val type: GameType,
    val players: List<GamePlayer>,
    val targetScore: Int,
    val scores: Map<String, Int>,
    val history: List<String>,
    val startedAt: Timestamp,
    val status: String
)

object GameRepository {

    private const val TAG =
        "GameRepository"

    private fun currentUserOrError(
        onError: (String) -> Unit
    ) =
        DurakAuthSession.current()
            .also {
                if (
                    it ==
                    null
                ) {
                    onError(
                        "Пользователь не авторизован"
                    )
                }
            }

    private fun toLoadedGame(
        game: ServerLoadedGame
    ): LoadedGame {

        val type =
            if (
                game.gameType ==
                "classic"
            ) {
                GameType.CLASSIC
            } else {
                GameType.CUSTOM
            }

        val players =
            game.players
                .map {
                    GamePlayer(
                        id =
                            it.id,
                        name =
                            it.name,
                        gender =
                            it.gender,
                        isCore =
                            it.isCore,
                        isGuest =
                            it.isGuest
                    )
                }

        val startedAt =
            Timestamp(
                Date(
                    game.startedAtEpochMillis
                        .coerceAtLeast(
                            0L
                        )
                )
            )

        return LoadedGame(
            id =
                game.id,
            type =
                type,
            players =
                players,
            targetScore =
                game.targetScore,
            scores =
                game.scores,
            history =
                game.history,
            startedAt =
                startedAt,
            status =
                game.status
        )
    }

    // ========================================================
    // CREATE GAME
    // ========================================================

    fun createGame(
        setup: GameSetup,
        onSuccess: (LoadedGame) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .createGame(
                user =
                    user,
                setup =
                    setup,
                isTest =
                    TEST_MODE,
                onSuccess = {
                        serverGame ->

                    onSuccess(
                        toLoadedGame(
                            serverGame
                        )
                    )
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // OPTIMISTIC ACTION QUEUE
    // ========================================================

    fun applyActions(
        gameId: String,
        actions: List<QueuedGameAction>,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        if (
            actions.isEmpty()
        ) {
            onSuccess()
            return
        }

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .applyGameActions(
                user =
                    user,
                gameId =
                    gameId,
                actions =
                    actions,
                onSuccess = {
                    onSuccess()
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // LOAD CURRENT STATE — VPS FIRST, FIRESTORE FALLBACK
    // ========================================================

    fun loadState(
        gameId: String,
        onSuccess: (
            scores: Map<String, Int>,
            history: List<String>
        ) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            DurakAuthSession.current()

        if (
            user ==
            null
        ) {
            onError(
                "Пользователь не авторизован"
            )
            return
        }

        DurakServerApi
            .loadGameState(
                user =
                    user,
                gameId =
                    gameId,
                onSuccess = {
                        state ->

                    onSuccess(
                        state.scores,
                        state.history
                    )
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // LEGACY SINGLE ACTION METHODS — NOW WRAPPERS OVER VPS
    // ========================================================

    fun addPoint(
        gameId: String,
        playerId: String,
        onSuccess: (
            scores: Map<String, Int>,
            history: List<String>
        ) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .applyGameActions(
                user =
                    user,
                gameId =
                    gameId,
                actions =
                    listOf(
                        QueuedGameAction(
                            type =
                                GameActionType.ADD_POINT,
                            playerId =
                                playerId
                        )
                    ),
                onSuccess = {
                        state ->

                    onSuccess(
                        state.scores,
                        state.history
                    )
                },
                onError =
                    onError
            )
    }

    fun undoLastPoint(
        gameId: String,
        onSuccess: (
            scores: Map<String, Int>,
            history: List<String>
        ) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .applyGameActions(
                user =
                    user,
                gameId =
                    gameId,
                actions =
                    listOf(
                        QueuedGameAction(
                            type =
                                GameActionType.UNDO_LAST
                        )
                    ),
                onSuccess = {
                        state ->

                    onSuccess(
                        state.scores,
                        state.history
                    )
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // PAUSE / RESUME
    // ========================================================

    fun pauseGame(
        gameId: String,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .pauseGame(
                user =
                    user,
                gameId =
                    gameId,
                onSuccess =
                    onSuccess,
                onError =
                    onError
            )
    }

    fun resumeGame(
        gameId: String,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .resumeGame(
                user =
                    user,
                gameId =
                    gameId,
                onSuccess =
                    onSuccess,
                onError =
                    onError
            )
    }

    // ========================================================
    // STATUS — VPS FIRST, FIRESTORE FALLBACK
    // ========================================================

    fun loadGameStatus(
        gameId: String,
        onSuccess: (String) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            DurakAuthSession.current()

        if (
            user ==
            null
        ) {
            onError(
                "Пользователь не авторизован"
            )
            return
        }

        DurakServerApi
            .loadGameStatus(
                user =
                    user,
                gameId =
                    gameId,
                onSuccess =
                    onSuccess,
                onError =
                    onError
            )
    }

    // ========================================================
    // TARGET SCORE
    // ========================================================

    fun updateTargetScore(
        gameId: String,
        newTargetScore: Int,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        if (
            newTargetScore !in
            2..99
        ) {
            onError(
                "Лимит должен быть от 2 до 99"
            )
            return
        }

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        DurakServerApi
            .updateTargetScore(
                user =
                    user,
                gameId =
                    gameId,
                newTargetScore =
                    newTargetScore,
                onSuccess =
                    onSuccess,
                onError =
                    onError
            )
    }

    // ========================================================
    // LATEST UNFINISHED — VPS FIRST, FIRESTORE FALLBACK
    // ========================================================

    fun loadLatestUnfinishedGame(
        onSuccess: (LoadedGame?) -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            DurakAuthSession.current()

        if (
            user ==
            null
        ) {
            onError(
                "Пользователь не авторизован"
            )
            return
        }

        DurakServerApi
            .loadLatestUnfinishedGame(
                user =
                    user,
                isTest =
                    TEST_MODE,
                onSuccess = {
                        game ->

                    onSuccess(
                        game?.let {
                            toLoadedGame(
                                it
                            )
                        }
                    )
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // FINISH — VPS, FIRESTORE MIRROR + POSTGRES
    // ========================================================

    fun finishGame(
        gameId: String,
        loserId: String,
        finishedByUid: String,
        finishedByName: String,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        /*
         * finishedByUid / finishedByName оставлены в сигнатуре,
         * чтобы не ломать существующий MainActivity.
         * Сервер определяет пользователя по session token.
         */
        DurakServerApi
            .finishGame(
                user =
                    user,
                gameId =
                    gameId,
                loserId =
                    loserId,
                onSuccess = {
                    onSuccess()
                },
                onError =
                    onError
            )
    }

    // ========================================================
    // CANCEL — VPS, FIRESTORE AUDIT + POSTGRES
    // ========================================================

    fun cancelGame(
        gameId: String,
        cancelledByUid: String,
        cancelledByName: String,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) {

        val user =
            currentUserOrError(
                onError
            )
                ?: return

        /*
         * cancelledByUid / cancelledByName оставлены ради
         * совместимости с существующим UI. Сервер берёт актёра
         * из проверенного session token.
         */
        DurakServerApi
            .cancelGame(
                user =
                    user,
                gameId =
                    gameId,
                onSuccess =
                    onSuccess,
                onError =
                    onError
            )
    }
}
