package dev.inmo.postssystem.client

import dev.inmo.postssystem.client.ui.fsm.*
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo
import kotlinx.serialization.StringFormat
import org.w3c.dom.*

class OneStateUIFSMStatesRepo(
    private val serialFormat: StringFormat,
    private val storage: Storage,
    private val initialState: UIFSMState = DefaultAuthUIFSMState
) : DefaultStatesManagerRepo<UIFSMState> {
    private val String.storageKey
        get() = "${FSMStateSettingsFieldPrefix}$this"
    private val String.UIFSMState
        get() = runCatching {
            serialFormat.decodeFromString(UIFSMStateSerializer, this)
        }.onFailure { it.printStackTrace() }.getOrNull()

    init {
        if (states().isEmpty()) {
            setState(initialState)
        }
    }

    private fun setState(state: UIFSMState) {
        storage[state.context.storageKey] = serialFormat.encodeToString(UIFSMStateSerializer, state)
    }

    override suspend fun getContextState(context: Any): UIFSMState? {
        return when (context) {
            is String -> storage[context.storageKey] ?.UIFSMState ?: return DefaultAuthUIFSMState
            else -> null
        }
    }

    override suspend fun contains(context: Any): Boolean = when (context) {
        is String -> storage.get(context) ?.UIFSMState != null
        else -> super.contains(context)
    }

    private fun states(): List<UIFSMState> = storage.iterator().asSequence().mapNotNull { (k, v) ->
        if (k.startsWith(FSMStateSettingsFieldPrefix)) {
            v.UIFSMState
        } else {
            null
        }
    }.toList()

    override suspend fun getStates(): List<UIFSMState> = states()

    override suspend fun removeState(state: UIFSMState) {
        storage.removeItem((state.context as? String) ?.storageKey ?: return)
    }

    override suspend fun set(state: UIFSMState) {
        setState(state)
    }

    companion object {
        private const val FSMStateSettingsFieldPrefix = "UIFSMState_"
    }
}
