package com.tencent.liteav.demo.player.viewmodel

import android.content.Context
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.tencent.liteav.demo.player.util.ModelProvider
import com.tencent.liteav.demo.superplayer.database.entity.CountDown
import com.tencent.liteav.demo.superplayer.database.entity.History
import com.tencent.liteav.demo.superplayer.database.entity.Record
import com.tencent.liteav.demo.superplayer.database.repo.PlayerRepository
import com.tencent.liteav.demo.superplayer.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.*

class PlayerViewModel(
    private val courseId: String,
    private val repository: PlayerRepository,
) : ViewModel(),
    TimersUtil.Listener,
    CountDownUtil.OnTickListener,
    HistoryUtil.Listener,
    PlayerUtil.Listener {
    companion object {
        val TAG = PlayerViewModel::class.java.simpleName.toString()
    }

    init {
        TimersUtil.addListener(this)
        HistoryUtil.addListener(this)
        PlayerUtil.addListener(this)
        CountDownUtil.addListener(this)
    }

    override fun onCleared() {
        super.onCleared()

        HistoryUtil.removeListener(this)
        TimersUtil.removeListener(this)
        PlayerUtil.removeListener(this)
        CountDownUtil.removeListener(this)
    }

    private var isPlaying: Boolean = false

    private lateinit var countDown: CountDown

    val toastStr: MutableLiveData<String> = MutableLiveData()

    fun loadConfig(context: Context) = viewModelScope.launch(Dispatchers.IO) {
        val common = context.getSharedPreferences("player_timer", Context.MODE_PRIVATE)
        val defaultType = common.getInt("type", 0)
        val defaultValue = common.getInt("value", 0)
        val defaultDate = common.getString("datetime", "20220831000000")!!

        val default = CountDown(
            id = "global",
            type = defaultType,
            value = defaultValue,
            rest = defaultValue,
            datetime = defaultDate,
        )
        val special = repository.findHasCountDown(courseId)

        if (special == null) {
            countDown = default
        } else {
            countDown = special
        }

        resetCountDown()
        setCountDown(countDown, false)

        for (record in ModelProvider.records) {
            if (!record.aiCourseItemId.isNullOrBlank()
                && !record.intervals.isNullOrBlank()
                && record.lastTime != null
                && record.validDuration != null
            )
                repository.insertRecord(record = Record(
                    aiCourseItemId = record.aiCourseItemId!!,
                    intervals = record.intervals!!,
                    lastTime = record.lastTime!!,
                    validDuration = record.validDuration!!,
                    courseId = ModelProvider.courseId,
                ))
        }
    }

    private fun resetCountDown() {
        if (countDown.type == CountDown.TYPE_DURATION) {
            if (countDown.rest > 0) {
                val current = SimpleDateFormat("yyyy-MM-dd").format(Date())

                if (countDown.datetime != current) {
                    countDown = countDown.copyWith(
                        rest = countDown.value
                    )
                    saveCountDown(countDown)
                }
            }
        }
    }

    /* 开启定时器 */
    private fun setCountDown(countDown: CountDown, forceSend: Boolean) {
        if (countDown.type == CountDown.TYPE_DURATION) {
            CountDownUtil.getInstance().reset(countDown.rest.toLong(), isPlaying)
        } else {
            CountDownUtil.getInstance().pause()
        }

        // 如果定时器已经到时间了 则直接进入锁定状态
        if (!forceSend && countDown.type != 0 && countDown.rest <= 0) {
            sendTimeout(true)
        } else {
            sendTimeout(false)
        }
    }

    fun checkCanPlay(): Boolean {
        return if (checkTimeout(countDown)) {
            sendTimeout(false)
            true
        } else {
            sendTimeout(true)
            false
        }
    }

    override fun onHistory(start: Long, end: Long, sectionId: String) {
        val history = History(
            start = start,
            end = end,
            courseId = courseId,
            sectionId = sectionId,
            date = SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(Date()),
            countDown = countDown.datetime,
        )

        viewModelScope.launch(Dispatchers.IO) {
            repository.insertHistory(history)
        }
    }

    override fun onNewTimer(type: Int, value: Int) {
        Log.d("PVM", "onListen: $type , $value")

        var rest = value
        if (type == CountDown.TYPE_EPISODE) {
            rest = value - 1
        }

        countDown = CountDown(
            id = courseId,
            type = type,
            value = value,
            rest = rest,
            datetime = SimpleDateFormat("yyyy-MM-dd").format(Date())
        )

        countDown.let {
            setCountDown(it, true)
            saveCountDown(it)
        }
    }


    override fun onTimeout(util: CountDownUtil?) {
        util?.pause()
        sendTimeout(true)
        onStop()
    }


    private fun checkTimeout(countDown: CountDown): Boolean {
        countDown.also {
            if (it.type == CountDown.TYPE_DURATION) {
                return checkDurationTimeout()
            } else if (it.type == CountDown.TYPE_EPISODE) {
                return checkEpisodeTimeout()
            } else {
                return true
            }

        }
    }

    private fun checkEpisodeTimeout(): Boolean {
        val rest = countDown.rest - 1
        countDown = countDown.copyWith(rest = rest)
        saveCountDown(countDown)
        return countDown.rest >= 0
    }


    private fun checkDurationTimeout(): Boolean {
        val rest = countDown.rest - CountDownUtil.getInstance().count
        countDown = countDown.copyWith(rest = rest.toInt())
        setupTimer(countDown.rest.toLong())
        saveCountDown(countDown)
        return countDown.rest > 0
    }

    fun onStop() {
        Log.d(TAG, "onExit")

        if (countDown.type == CountDown.TYPE_DURATION) {
            val rest = countDown.rest - CountDownUtil.getInstance().count
            countDown = countDown.copyWith(rest = rest.toInt())
            saveCountDown(countDown)
        }
    }

    private fun setupTimer(count: Long) {
        if (countDown.type == CountDown.TYPE_DURATION) {
            CountDownUtil.getInstance().reset(count, isPlaying)
        }
    }

    /* 保存对该门课程单独设置的定时 */
    private fun saveCountDown(countDown: CountDown) = viewModelScope.launch(Dispatchers.IO) {
        repository.insertCountDown(countDown)
    }

    private fun sendTimeout(state: Boolean) {
        viewModelScope.launch(Dispatchers.Main) {
            TimeoutUtil.sendTimeout(state)
        }
    }

    override fun onStatePlay() {
        isPlaying = true

        if (countDown.type == CountDown.TYPE_DURATION) {
            CountDownUtil.getInstance().startOrResume()
        }
    }

    override fun onStateResume() {
        isPlaying = true

        if (countDown.type == CountDown.TYPE_DURATION) {
            CountDownUtil.getInstance().startOrResume()
        }
    }

    override fun onStatePause() {
        isPlaying = false

        if (countDown.type == CountDown.TYPE_DURATION) {
            (CountDownUtil.getInstance()).pause()
        }
    }

    override fun onStateStop() {
        isPlaying = false

        if (countDown.type == CountDown.TYPE_DURATION) {
            (CountDownUtil.getInstance()).pause()
        }
    }

    override fun onStateLoading() {
    }
}

class PlayerViewModelFactory(
    private val courseId: String,
    private val repository: PlayerRepository,
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(PlayerViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return PlayerViewModel(courseId, repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}