package com.pixelized.biblib.ui.screen.home.detail

import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.biblib.R
import com.pixelized.biblib.network.client.IBibLibClient
import com.pixelized.biblib.repository.book.IBookRepository
import com.pixelized.biblib.utils.extention.toDetailUio
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class BookDetailViewModel @Inject constructor(
    private val bookRepository: IBookRepository,
    private val client: IBibLibClient,
) : ViewModel() {

    private var detailJob: Job? = null
    private val _detail = mutableStateOf<BookDetailUio?>(null)
    val detail: State<BookDetailUio?> get() = _detail

    private var sendJob: Job? = null
    private val _sendStatus = MutableSharedFlow<Boolean>()
    val sendStatus: Flow<Boolean> get() = _sendStatus

    private val _sendingFlow = MutableSharedFlow<Boolean>()
    val sendingFlow: Flow<Boolean> get() = _sendingFlow

    private val _error = MutableSharedFlow<BookDetailUioErrorUio>()
    val error: Flow<BookDetailUioErrorUio> get() = _error

    fun getDetail(bookId: Int) {
        detailJob?.cancel()
        detailJob = viewModelScope.launch(Dispatchers.IO) {
            try {
                _detail.value = getCacheBookDetail(id = bookId)
                _detail.value = getBookDetail(id = bookId)
            } catch (exception: Exception) {
                _error.emit(toDetailErrorUio(bookId = bookId))
            }
        }
    }

    @Suppress("LiftReturnOrAssignment")
    fun send(bookId: Int, email: String, format: String) {
        sendJob?.cancel()
        sendJob = viewModelScope.launch(Dispatchers.IO) {
            _sendingFlow.emit(true)
            var isSuccess = false
            try {
                val data = client.service.send(bookId = bookId, mail = email, format = format)
                isSuccess = data.containsKey("ok")
            } catch (exception: Exception) {
                _error.emit(toSendBookUio(bookId = bookId, mail = email, format = format))
                isSuccess = false
            } finally {
                _sendingFlow.emit(false)
                if (isSuccess) {
                    _sendStatus.emit(true)
                    delay(300 + 2000)
                    _sendStatus.emit(false)
                }
            }
        }
    }

    private fun getCacheBookDetail(id: Int): BookDetailUio {
        return bookRepository.getBook(id = id).toDetailUio(placeHolder = true)
    }

    private suspend fun getBookDetail(id: Int): BookDetailUio {
        return bookRepository.getBookDetail(id = id).toDetailUio(placeHolder = false)
    }

    private fun toDetailErrorUio(bookId: Int) = BookDetailUioErrorUio.GetDetailInput(
        message = R.string.error_get_book_detail_message,
        action = R.string.error_get_book_detail_action,
        bookId = bookId,
    )

    private fun toSendBookUio(
        bookId: Int,
        mail: String,
        format: String
    ) = BookDetailUioErrorUio.SendBookInput(
        message = R.string.error_send_book_message,
        action = R.string.error_send_book_action,
        bookId = bookId,
        mail = mail,
        format = format,
    )
}