package net.sergeych.toread

import net.sergeych.toread.fb2.Fb2Book
import net.sergeych.toread.fb2.Fb2Format

internal sealed interface AppState {
    data object LoadingLibrary : AppState
    data class Library(
        val items: List<LibraryItem>,
        val scanPath: String,
        val message: String? = null,
    ) : AppState

    data class Scan(
        val items: List<LibraryItem>,
        val scanPath: String,
        val message: String? = null,
    ) : AppState

    data class Reader(
        val fileId: String,
        val book: Fb2Book,
        val libraryItems: List<LibraryItem>,
        val scanPath: String,
        val message: String? = null,
    ) : AppState

    data class BookInfo(
        val fileId: String,
        val book: Fb2Book,
        val libraryItems: List<LibraryItem>,
        val scanPath: String,
        val message: String? = null,
    ) : AppState

    data class Error(val message: String) : AppState
}

internal suspend fun loadStartupState(): AppState {
    val library = loadLibraryState()
    if (library !is AppState.Library) return library
    loadPlatformOpenBookRequest()?.let { request ->
        return runCatching {
            AppState.Reader(
                fileId = request.id,
                book = Fb2Format.parse(request.bytes, request.displayName),
                libraryItems = library.items,
                scanPath = library.scanPath,
                message = library.message,
            )
        }.getOrElse {
            AppState.Library(library.items, library.scanPath, it.message ?: "Could not open ${request.displayName}.")
        }
    }
    val activeFileId = loadActiveReadingFileId() ?: return library
    val item = loadLibraryItem(activeFileId)
    if (item == null) {
        saveActiveReadingFileId(null)
        return library
    }
    return runCatching {
        val bytes = openLibraryBook(activeFileId) ?: error("Book file is not available.")
        AppState.Reader(
            fileId = activeFileId,
            book = Fb2Format.parse(bytes, item.storageUri ?: item.title),
            libraryItems = library.items,
            scanPath = library.scanPath,
            message = library.message,
        )
    }.getOrElse {
        saveActiveReadingFileId(null)
        AppState.Library(library.items, library.scanPath, it.message ?: "Could not reopen last book.")
    }
}

internal suspend fun loadLibraryState(message: String? = null, scanPath: String? = null): AppState =
    runCatching {
        AppState.Library(
            items = emptyList(),
            scanPath = scanPath ?: defaultLibraryScanPath().orEmpty(),
            message = message,
        )
    }.getOrElse {
        AppState.Error(it.message ?: "Could not open library.")
    }
