package com.pixelized.desktop.lwa.repository.settings

import com.pixelized.desktop.lwa.repository.settings.model.Settings
import com.pixelized.desktop.lwa.repository.settings.model.SettingsJson
import com.pixelized.desktop.lwa.usecase.SettingsUseCase
import com.pixelized.shared.lwa.utils.PathProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import java.io.File

class SettingsStore(
    private val pathProvider: PathProvider,
    private val factory: SettingsFactory,
    private val useCase: SettingsUseCase,
    private val jsonFormatter: Json,
) {
    private val _settingsFlow = MutableStateFlow(value = useCase.defaultSettings())
    val settingsFlow: StateFlow<Settings> = _settingsFlow

    init {
        // create the directory
        File(pathProvider.storePath()).also { it.mkdirs() }
        // load the data.
        runBlocking {
            try {
                _settingsFlow.value = load()
            } catch (exception: Exception) {
                println(exception) // TODO proper exception handling
            }
        }
    }

    @Throws(
        SettingsStoreException::class,
        FileWriteException::class,
        JsonConversionException::class,
    )
    fun save(settings: Settings) {
        val json = try {
            factory.convertToJson(settings = settings).let(jsonFormatter::encodeToString)
        } catch (exception: Exception) {
            throw JsonConversionException(root = exception)
        }
        try {
            val file = settingsFile()
            file.writeText(
                text = json,
                charset = Charsets.UTF_8,
            )
        } catch (exception: Exception) {
            throw FileWriteException(
                root = exception
            )
        }
        _settingsFlow.value = settings
    }

    private fun load(): Settings {
        return settingsFile().let { file ->
            val json = try {
                file.readText(charset = Charsets.UTF_8)
            } catch (exception: Exception) {
                throw FileReadException(
                    root = exception
                )
            }
            if (json.isBlank()) {
                return useCase.defaultSettings()
            }
            try {
                factory.convertFromJson(
                    json = jsonFormatter.decodeFromString<SettingsJson>(json)
                )
            } catch (exception: Exception) {
                throw JsonConversionException(root = exception)
            }
        }
    }

    private fun settingsFile(): File {
        return File("${pathProvider.storePath()}settings.json")
    }

    sealed class SettingsStoreException(root: Exception) : Exception(root)
    class JsonConversionException(root: Exception) : SettingsStoreException(root)
    class FileWriteException(root: Exception) : SettingsStoreException(root)
    class FileReadException(root: Exception) : SettingsStoreException(root)
}

