package de.tsschulz.tt_tagebuch.shared.state

import de.tsschulz.tt_tagebuch.shared.api.ApiLogsApi
import de.tsschulz.tt_tagebuch.shared.api.models.ApiLogDetailDto
import de.tsschulz.tt_tagebuch.shared.api.models.ApiLogListRowDto
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update

data class ApiLogsState(
    val logs: List<ApiLogListRowDto> = emptyList(),
    val total: Int = 0,
    val offset: Int = 0,
    val limit: Int = 50,
    val isLoading: Boolean = false,
    val error: String? = null,
)

class ApiLogsManager(
    private val apiLogsApi: ApiLogsApi,
) {
    private val _state = MutableStateFlow(ApiLogsState())
    val state: StateFlow<ApiLogsState> = _state.asStateFlow()

    fun clear() {
        _state.value = ApiLogsState()
    }

    suspend fun load(
        logType: String? = null,
        method: String? = null,
        statusCode: Int? = null,
        pathContains: String? = null,
        resetOffset: Boolean = false,
        offsetOverride: Int? = null,
    ) {
        val offset = offsetOverride ?: if (resetOffset) 0 else _state.value.offset
        val limit = _state.value.limit
        _state.update { it.copy(isLoading = true, error = null, offset = offset) }
        try {
            val page = apiLogsApi.listLogs(
                limit = limit,
                offset = offset,
                logType = logType,
                method = method,
                statusCode = statusCode,
                pathContains = pathContains,
            )
            _state.update {
                it.copy(
                    logs = page.logs,
                    total = page.total,
                    limit = page.limit.takeIf { l -> l > 0 } ?: limit,
                    offset = page.offset,
                    isLoading = false,
                    error = null,
                )
            }
        } catch (t: Throwable) {
            _state.update {
                it.copy(
                    isLoading = false,
                    error = t.toUserMessage("Logs konnten nicht geladen werden"),
                )
            }
        }
    }

    suspend fun nextPage(
        logType: String? = null,
        method: String? = null,
        statusCode: Int? = null,
        pathContains: String? = null,
    ) {
        val s = _state.value
        if (s.offset + s.logs.size >= s.total) return
        load(logType, method, statusCode, pathContains, offsetOverride = s.offset + s.limit)
    }

    suspend fun previousPage(
        logType: String? = null,
        method: String? = null,
        statusCode: Int? = null,
        pathContains: String? = null,
    ) {
        val s = _state.value
        if (s.offset <= 0) return
        load(logType, method, statusCode, pathContains, offsetOverride = (s.offset - s.limit).coerceAtLeast(0))
    }

    suspend fun fetchDetail(id: Int): ApiLogDetailDto? =
        try {
            apiLogsApi.getLog(id)
        } catch (_: Throwable) {
            null
        }
}
