/*
 * Book's Story — free and open-source Material You eBook reader.
 * Copyright (C) 2024-2026 Acclorite
 * SPDX-License-Identifier: GPL-3.0-only
 */

package org.dueattendant149.bookshelf.data.settings

import androidx.datastore.preferences.core.stringPreferencesKey
import org.dueattendant149.bookshelf.data.local.data_store.DataStore
import org.dueattendant149.bookshelf.domain.util.isValidUri
import org.dueattendant149.bookshelf.domain.util.normalizeUri
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ServerSettings
    @Inject
    constructor(
        private val dataStore: DataStore,
    ) {
        private val bookshelfUrlKey = stringPreferencesKey("bookshelf_url")
        private val absUrlKey = stringPreferencesKey("abs_url")
        private val absTokenKey = stringPreferencesKey("abs_token")

        suspend fun getBookshelfUrl(): String? =
            dataStore.getNullableData(bookshelfUrlKey)?.normalizeIfValid()

        suspend fun setBookshelfUrl(value: String) {
            dataStore.putData(bookshelfUrlKey, value.normalizeIfValid() ?: value.trim())
        }

        suspend fun getAbsUrl(): String? =
            dataStore.getNullableData(absUrlKey)?.normalizeIfValid()

        suspend fun setAbsUrl(value: String) {
            dataStore.putData(absUrlKey, value.normalizeIfValid() ?: value.trim())
        }

        suspend fun getAbsToken(): String? = dataStore.getNullableData(absTokenKey)?.trim()
        suspend fun setAbsToken(value: String) = dataStore.putData(absTokenKey, value.trim())

        suspend fun hasCredentials(): Boolean = getMissingCredentialsError() == null

        /**
         * Returns a user-facing error message if any required credential is missing or invalid,
         * or null when all credentials are present.
         */
        suspend fun getMissingCredentialsError(): String? {
            val bookshelfUrl = dataStore.getNullableData(bookshelfUrlKey)
            if (bookshelfUrl.isNullOrBlank()) {
                return "Bookshelf API URL is missing"
            }
            if (!bookshelfUrl.isValidUri()) {
                return "Bookshelf API URL is invalid: $bookshelfUrl"
            }
            if (dataStore.getNullableData(absUrlKey).isNullOrBlank()) {
                return "Audiobookshelf URL is missing"
            }
            if (dataStore.getNullableData(absTokenKey).isNullOrBlank()) {
                return "ABS token is missing"
            }
            return null
        }

        suspend fun validateBookshelfUrl(): Result<String> {
            val url = dataStore.getNullableData(bookshelfUrlKey)?.trim()
            return when {
                url.isNullOrBlank() -> Result.failure(IllegalArgumentException("Bookshelf URL is empty"))
                !url.isValidUri() -> Result.failure(IllegalArgumentException("Bookshelf URL is invalid: $url"))
                else -> Result.success(url.normalizeUri())
            }
        }

        suspend fun clear() {
            setBookshelfUrl("")
            setAbsUrl("")
            setAbsToken("")
        }

        private fun String.normalizeIfValid(): String? {
            val trimmed = trim()
            return if (trimmed.isValidUri()) trimmed.normalizeUri() else null
        }
    }
