package com.example.modifier.data

import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asFlow
import com.example.modifier.BuildConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlin.coroutines.coroutineContext

val Context.appStateDataStore by preferencesDataStore(name = "${BuildConfig.APPLICATION_ID}.appState")

class AppStateRepository(
    val context: Context
) {

    private object PreferencesKeys {
        val SEND = booleanPreferencesKey("send")
        val EXECUTED_NUM = intPreferencesKey("executed_num")
        val SUCCESS_NUM = intPreferencesKey("success_num")
        val REQUESTED_NUM = intPreferencesKey("requested_num")
    }

    private val appRuntimeFlags = MutableLiveData(AppRuntimeFlags())

    private val appStateFlow =
        context.appStateDataStore.data.combine(appRuntimeFlags.asFlow()) { preferences, runtimeFlags ->
            AppState(
                send = preferences[PreferencesKeys.SEND] ?: false,
                executedNum = preferences[PreferencesKeys.EXECUTED_NUM] ?: 0,
                successNum = preferences[PreferencesKeys.SUCCESS_NUM] ?: 0,
                requestedNum = preferences[PreferencesKeys.REQUESTED_NUM] ?: 0,
                running = runtimeFlags.running,
                requesting = runtimeFlags.requesting,
                preparing = runtimeFlags.preparing,
                checkingConnection = runtimeFlags.checkingConnection,
                busy = runtimeFlags.running || runtimeFlags.requesting || runtimeFlags.preparing || runtimeFlags.checkingConnection
            )
        }

    suspend fun getAppState() = appStateFlow.stateIn(CoroutineScope(coroutineContext))

    suspend fun incrementExecutedNum(success: Boolean) {
        context.appStateDataStore.edit { preferences ->
            val executedNum = (preferences[PreferencesKeys.EXECUTED_NUM] ?: 0) + 1
            preferences[PreferencesKeys.EXECUTED_NUM] = executedNum
            if (success) {
                val successNum = (preferences[PreferencesKeys.SUCCESS_NUM] ?: 0) + 1
                preferences[PreferencesKeys.SUCCESS_NUM] = successNum
            }
        }
    }

    suspend fun incrementRequestedNum() {
        context.appStateDataStore.edit { preferences ->
            val requestedNum = (preferences[PreferencesKeys.REQUESTED_NUM] ?: 0) + 1
            preferences[PreferencesKeys.REQUESTED_NUM] = requestedNum
        }
    }

    suspend fun resetExecutedNum() {
        context.appStateDataStore.edit { preferences ->
            preferences[PreferencesKeys.EXECUTED_NUM] = 0
        }
    }

    suspend fun resetSuccessNum() {
        context.appStateDataStore.edit { preferences ->
            preferences[PreferencesKeys.SUCCESS_NUM] = 0
        }
    }

    suspend fun resetRequestedNum() {
        context.appStateDataStore.edit { preferences ->
            preferences[PreferencesKeys.REQUESTED_NUM] = 0
        }
    }

    suspend fun updateSend(send: Boolean) {
        context.appStateDataStore.edit { preferences ->
            preferences[PreferencesKeys.SEND] = send
        }
    }

    fun updateRuntimeFlags(
        running: Boolean? = null,
        requesting: Boolean? = null,
        preparing: Boolean? = null,
        checkingConnection: Boolean? = null
    ) {
        val value = appRuntimeFlags.value ?: AppRuntimeFlags()
        appRuntimeFlags.postValue(
            value.copy(
                running = running ?: value.running,
                requesting = requesting ?: value.requesting,
                preparing = preparing ?: value.preparing,
                checkingConnection = checkingConnection ?: value.checkingConnection
            )
        )
    }
}