package com.example.modifier.repo

import android.content.Context
import android.util.Log
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.example.modifier.BuildConfig
import com.example.modifier.baseTag
import com.example.modifier.data.AppState
import com.example.modifier.enums.ReqState
import com.example.modifier.utils.getContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

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

class AppStateRepo private constructor(private val context: Context) {

    companion object {
        private const val TAG = "${baseTag}/AppStateRepo"
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { AppStateRepo(getContext()) }
    }

    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")
    }

    val appState = MutableStateFlow(
        AppState(
            send = false,
            executedNum = 0,
            successNum = 0,
            requestedNum = 0,
            running = false,
            preparing = false,
            checkingConnection = false,
            suspended = false,
            reqState = ReqState.NONE
        )
    )

    init {
        CoroutineScope(Dispatchers.IO).launch {
            context.appStateDataStore.data.collect { preferences ->
                appState.update {
                    it.copy(
                        send = preferences[PreferencesKeys.SEND] ?: false,
                        executedNum = preferences[PreferencesKeys.EXECUTED_NUM] ?: 0,
                        successNum = preferences[PreferencesKeys.SUCCESS_NUM] ?: 0,
                        requestedNum = preferences[PreferencesKeys.REQUESTED_NUM] ?: 0
                    )
                }
            }
        }
    }

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

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

    suspend fun setRequestedNum(num: Int) {
        context.appStateDataStore.edit { preferences ->
            val requestedNum = (preferences[PreferencesKeys.REQUESTED_NUM] ?: 0) + 1
            Log.i(TAG, "incrementRequestedNum: $requestedNum")
            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,
        preparing: Boolean? = null,
        checkingConnection: Boolean? = null,
        suspended: Boolean? = null,
        reqState: ReqState? = null,
        storing: Boolean? = null
    ) {
        appState.update {
            it.copy(
                running = running ?: it.running,
                preparing = preparing ?: it.preparing,
                checkingConnection = checkingConnection ?: it.checkingConnection,
                suspended = suspended ?: it.suspended,
                reqState = reqState ?: it.reqState,
                storing = storing ?: it.storing
            )
        }
    }
}
