package dev.inmo.postssystem.client

import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.pagination.utils.reverse
import dev.inmo.micro_utils.repos.KeyValueRepo
import kotlinx.browser.localStorage
import kotlinx.coroutines.flow.*
import org.w3c.dom.get
import org.w3c.dom.set

object CookiesKeyValueRepo : KeyValueRepo<String, String> {
    private val _onNewValue = MutableSharedFlow<Pair<String, String>>()
    private val _onValueRemoved = MutableSharedFlow<String>()
    override val onNewValue: Flow<Pair<String, String>> = _onNewValue.asSharedFlow()
    override val onValueRemoved: Flow<String> = _onValueRemoved.asSharedFlow()

    override suspend fun contains(key: String): Boolean = localStorage.iterator().asSequence().any { it.first == key }

    override suspend fun count(): Long = localStorage.length.toLong()

    override suspend fun get(k: String): String? = localStorage[k]

    override suspend fun keys(
        v: String,
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<String> = localStorage.iterator().asSequence().mapNotNull {
        if (it.second == v) it.first else null
    }.toList().let {
        it.paginate(
            if (reversed) {
                pagination.reverse(it.count())
            } else {
                pagination
            }
        )
    }

    override suspend fun keys(
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<String> = localStorage.iterator().asSequence().map { it.first }.toList().let {
        it.paginate(
            if (reversed) {
                pagination.reverse(it.count())
            } else {
                pagination
            }
        )
    }

    override suspend fun values(
        pagination: Pagination,
        reversed: Boolean
    ): PaginationResult<String> = localStorage.iterator().asSequence().map { it.second }.toList().let {
        it.paginate(
            if (reversed) {
                pagination.reverse(it.count())
            } else {
                pagination
            }
        )
    }

    override suspend fun set(toSet: Map<String, String>) {
        toSet.forEach { (k, v) ->
            localStorage[k] = v
            _onNewValue.emit(k to v)
        }
    }

    override suspend fun unset(toUnset: List<String>) {
        toUnset.forEach {
            localStorage[it] ?.let { _ ->
                localStorage.removeItem(it)
                _onValueRemoved.emit(it)
            }
        }
    }
}
