/*
 * 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.presentation.bookshelf

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.dueattendant149.bookshelf.data.settings.ServerSettings
import org.dueattendant149.bookshelf.domain.model.cache.CacheStatus
import org.dueattendant149.bookshelf.domain.model.library.Book
import org.dueattendant149.bookshelf.domain.model.remote.RemoteLibrary
import org.dueattendant149.bookshelf.domain.use_case.cache.CacheBookUseCase
import org.dueattendant149.bookshelf.domain.use_case.cache.DeleteCacheUseCase
import org.dueattendant149.bookshelf.domain.use_case.cache.GetCacheStatusUseCase
import org.dueattendant149.bookshelf.domain.use_case.remote.FetchBooksUseCase
import org.dueattendant149.bookshelf.domain.use_case.remote.FetchLibrariesUseCase
import javax.inject.Inject

data class RemoteLibraryState(
    val libraries: List<RemoteLibrary> = emptyList(),
    val books: List<Book> = emptyList(),
    val selectedLibrary: RemoteLibrary? = null,
    val isLoading: Boolean = false,
    val error: String? = null,
    val cacheStatuses: Map<String, CacheStatus> = emptyMap(),
    val offlineOnly: Boolean = false,
)

@HiltViewModel
class RemoteLibraryModel
    @Inject
    constructor(
        private val fetchLibrariesUseCase: FetchLibrariesUseCase,
        private val fetchBooksUseCase: FetchBooksUseCase,
        private val cacheBookUseCase: CacheBookUseCase,
        private val deleteCacheUseCase: DeleteCacheUseCase,
        private val getCacheStatusUseCase: GetCacheStatusUseCase,
        private val serverSettings: ServerSettings,
    ) : ViewModel() {
        private val _state = MutableStateFlow(RemoteLibraryState())
        val state = _state.asStateFlow()
        private var cacheStatusJob: Job? = null

        init {
            loadLibraries()
        }

        fun loadLibraries() {
            viewModelScope.launch {
                _state.update { it.copy(isLoading = true, error = null) }
                if (!serverSettings.hasCredentials()) {
                    _state.update { it.copy(isLoading = false, error = "Server not configured") }
                    return@launch
                }
                val result = fetchLibrariesUseCase()
                _state.update {
                    it.copy(
                        isLoading = false,
                        libraries = result.getOrDefault(emptyList()),
                        error = result.exceptionOrNull()?.message,
                    )
                }
            }
        }

        fun selectLibrary(library: RemoteLibrary) {
            _state.update { it.copy(selectedLibrary = library, books = emptyList(), error = null) }
            loadBooks(library.id)
        }

        fun loadBooks(libraryId: String) {
            viewModelScope.launch {
                _state.update { it.copy(isLoading = true, error = null) }
                val result = fetchBooksUseCase(libraryId)
                _state.update {
                    it.copy(
                        isLoading = false,
                        books = result.getOrDefault(emptyList()),
                        error = result.exceptionOrNull()?.message,
                    )
                }
                observeCacheStatuses()
            }
        }

        fun cacheBook(book: Book) {
            viewModelScope.launch {
                val result = cacheBookUseCase(book)
                if (result.isFailure) {
                    _state.update {
                        it.copy(error = result.exceptionOrNull()?.message ?: "Cache failed")
                    }
                }
                observeCacheStatuses()
            }
        }

        fun deleteCache(book: Book) {
            viewModelScope.launch {
                val result = deleteCacheUseCase(book.remoteId)
                if (result.isFailure) {
                    _state.update {
                        it.copy(error = result.exceptionOrNull()?.message ?: "Delete cache failed")
                    }
                }
            }
        }

        fun toggleOfflineOnly() {
            _state.update { it.copy(offlineOnly = !it.offlineOnly) }
        }

        private fun observeCacheStatuses() {
            cacheStatusJob?.cancel()
            val remoteIds = state.value.books.map { it.remoteId }.filter { it.isNotBlank() }
            if (remoteIds.isEmpty()) {
                _state.update { it.copy(cacheStatuses = emptyMap()) }
                return
            }

            cacheStatusJob =
                viewModelScope.launch {
                    combine(
                        remoteIds.map { remoteId ->
                            getCacheStatusUseCase(remoteId)
                        },
                    ) { statuses ->
                        statuses.toList().associateBy { it.remoteId }
                    }.collect { statuses ->
                        _state.update { it.copy(cacheStatuses = statuses) }
                    }
                }
        }
    }
