package solutions.tretter.githugandroid

import android.content.Context
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStoreFile
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException

class PaneLayoutStore(private val context: Context) {
    private val dataStore = PreferenceDataStoreFactory.create(
        produceFile = { context.preferencesDataStoreFile("pane_layout_preferences") }
    )

    private val orderKey = stringPreferencesKey("pane_order")
    private val collapsedKey = stringPreferencesKey("pane_collapsed")
    private val weightsKey = stringPreferencesKey("pane_weights")

    val layoutFlow = dataStore.data
        .catch { error ->
            if (error is IOException) emit(emptyPreferences()) else throw error
        }
        .map { preferences ->
            val defaults = defaultPaneLayout()
            val order = preferences[orderKey]
                ?.split(',')
                ?.mapNotNull { value -> PaneId.entries.firstOrNull { it.name == value } }
                ?.let { parsed ->
                    val missing = PaneId.entries.filterNot { it in parsed }
                    parsed + missing
                }
                ?.takeIf { it.isNotEmpty() }
                ?: defaults.order

            val collapsed = preferences[collapsedKey]
                ?.split(',')
                ?.mapNotNull { value -> PaneId.entries.firstOrNull { it.name == value } }
                ?.toSet()
                ?: emptySet()

            val parsedWeights = preferences[weightsKey]
                ?.split(';')
                ?.mapNotNull { item ->
                    val parts = item.split(':', limit = 2)
                    val paneId = PaneId.entries.firstOrNull { it.name == parts.getOrNull(0) }
                    val weight = parts.getOrNull(1)?.toFloatOrNull()
                    if (paneId != null && weight != null) paneId to weight.coerceAtLeast(0.6f) else null
                }
                ?.toMap()
                .orEmpty()

            PaneLayout(
                order = order,
                collapsed = collapsed,
                weights = PaneId.entries.associateWith { pane -> parsedWeights[pane] ?: defaults.weights.getValue(pane) },
            )
        }

    suspend fun save(layout: PaneLayout) {
        dataStore.edit { preferences ->
            preferences[orderKey] = layout.order.joinToString(",") { it.name }
            preferences[collapsedKey] = layout.collapsed.joinToString(",") { it.name }
            preferences[weightsKey] = layout.order.joinToString(";") { pane ->
                "${pane.name}:${layout.weights[pane] ?: 1f}"
            }
        }
    }
}