/*
 * This file is part of SubTypo.
 *
 * SubTypo is free software: you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * SubTypo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with SubTypo.
 * If not, see <https://www.gnu.org/licenses/>.
 */

package com.teixeira0x.subtypo.ui.textlist.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.teixeira0x.subtypo.core.domain.usecase.subtitle.GetSubtitleUseCase
import com.teixeira0x.subtypo.core.domain.usecase.subtitle.UpdateSubtitleUseCase
import com.teixeira0x.subtypo.core.subtitle.model.Cue
import com.teixeira0x.subtypo.ui.textlist.mvi.CueListIntent
import com.teixeira0x.subtypo.ui.textlist.mvi.CueListViewEvent
import com.teixeira0x.subtypo.ui.textlist.mvi.CueListViewState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

@HiltViewModel
class CueListViewModel
@Inject
constructor(
  private val getSubtitleUseCase: GetSubtitleUseCase,
  private val updateSubtitleUseCase: UpdateSubtitleUseCase,
) : ViewModel() {

  companion object {
    private val cueTimeComparator =
      Comparator<Cue> { c1, c2 -> c1.startTime.compareTo(c2.startTime) }
  }

  private val _cueListViewState =
    MutableStateFlow<CueListViewState>(CueListViewState.Loading)
  val cueListViewState: StateFlow<CueListViewState>
    get() = _cueListViewState.asStateFlow()

  private val _playerPosition = MutableStateFlow(0L)
  val playerPosition: StateFlow<Long> = _playerPosition.asStateFlow()

  private val _customViewEvent = MutableSharedFlow<CueListViewEvent>()
  val customViewEvent: SharedFlow<CueListViewEvent> =
    _customViewEvent.asSharedFlow()

  var subtitleId: Long = 0
    private set

  fun doIntent(intent: CueListIntent) {
    when (intent) {
      is CueListIntent.LoadSubtitle -> loadSubtitle(intent)
      is CueListIntent.ShowSubtitleList -> showSubtitleList()
      is CueListIntent.SortCueListByTime -> sortCueListByTime()
      is CueListIntent.PlayerPause -> playerPause()
      is CueListIntent.PlayerSeekTo -> playerSeekTo(intent)
    }
  }

  private fun loadSubtitle(intent: CueListIntent.LoadSubtitle) {
    _cueListViewState.value = CueListViewState.Loading
    viewModelScope.launch {
      subtitleId = intent.subtitleId
      getSubtitleUseCase(intent.subtitleId).collect { subtitle ->
        _cueListViewState.value =
          CueListViewState.Loaded(subtitle?.cues ?: emptyList())
      }
    }
  }

  private fun showSubtitleList() {
    viewModelScope.launch {
      _customViewEvent.emit(CueListViewEvent.ShowSubtitleList)
    }
  }

  private fun sortCueListByTime() {
    viewModelScope.launch {
      val subtitle = getSubtitleUseCase(subtitleId).firstOrNull()
      if (subtitle != null) {
        updateSubtitleUseCase(
          subtitle.copy(cues = subtitle.cues.sortedWith(cueTimeComparator))
        )
      }
    }
  }

  private fun playerPause() {
    viewModelScope.launch {
      _customViewEvent.emit(CueListViewEvent.PlayerPause)
    }
  }

  private fun playerSeekTo(intent: CueListIntent.PlayerSeekTo) {
    viewModelScope.launch {
      _customViewEvent.emit(CueListViewEvent.PlayerSeekTo(intent.position))
    }
  }

  fun updatePlayerPosition(position: Long) {
    _playerPosition.value = position
  }
}
