package com.example.lexilearn.ui.views.pQuiz

import android.app.Application
import android.speech.tts.TextToSpeech
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.QuizQuestion
import com.example.lexilearn.data.repository.QuizRepository
import com.example.lexilearn.domain.models.ModelAnswer
import com.example.lexilearn.domain.models.ModelQuestion
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.util.Locale
import kotlin.math.max
import kotlin.random.Random

class QuizViewModel(application: Application) : AndroidViewModel(application),
    TextToSpeech.OnInitListener {
    private val quizRepository = QuizRepository()

    private var materialList: List<MaterialDataModel> = emptyList()

    private val _currentQuestion = MutableStateFlow<QuizQuestion?>(null)
    val currentQuestion: StateFlow<QuizQuestion?> = _currentQuestion

    private val _userAnswer = MutableStateFlow<String?>(null)
    val userAnswer: StateFlow<String?> = _userAnswer

    private val _isAnswerCorrect = MutableStateFlow<Boolean?>(null)
    val isAnswerCorrect: StateFlow<Boolean?> = _isAnswerCorrect

    private val _indexQuiz = MutableStateFlow(0)
    val indexQuiz: StateFlow<Int> = _indexQuiz

    // Update indexQuiz saat jawaban benar
    fun incrementIndexQuiz() {
        _indexQuiz.value += 1
    }

    private val _shuffledAnswerLetters = MutableStateFlow<List<ModelAnswer>>(emptyList())
    val shuffledAnswerLetters: StateFlow<List<ModelAnswer>> = _shuffledAnswerLetters


    private val _questionShuffled = MutableStateFlow<List<ModelQuestion>>(emptyList())
    val questionShuffled: StateFlow<List<ModelQuestion>> = _questionShuffled

    private val _isButtonVisible = mutableStateOf(false)
    val isButtonVisible: State<Boolean> get() = _isButtonVisible

    fun updateQuestionShuffled(index: Int, newData: ModelQuestion) {
        _questionShuffled.value = _questionShuffled.value.mapIndexed { i, item ->
            if (i == index) {
                item.copy(
                    data = newData.data,
                    showCard = true,
                    emp = newData.emp,
                    hasContent = true
                )
            } else {
                item
            }
        }
    }


    fun initMaterialData(material: List<MaterialDataModel>) {
        materialList = material;
    }


    fun randomQuestion() {
        val randomQuestionMode = Random.nextInt(1, 3)

        _currentQuestion.value =
            quizRepository.generateQuestion(materialList[_indexQuiz.value], randomQuestionMode, 2)

        val dataQuest =
            _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
                ModelQuestion(
                    id = (_indexQuiz.value * 100) + index + 1,
                    type = true,
                    data = "?",
                    showCard = false
                )
            } ?: emptyList()
        _questionShuffled.value = dataQuest

        val listAnswer =
            _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
                ModelAnswer(
                    id = (_indexQuiz.value * 100) + index + 1,
                    data = char.toString().lowercase()
                )
            } ?: emptyList()
        _shuffledAnswerLetters.value = listAnswer.shuffled()
    }


    private var tts: TextToSpeech? = null
    private val _isTTSInitialized = MutableLiveData(false)
    val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized

    init {
        tts = TextToSpeech(application, this)
        observeData()
    }

    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            tts?.language = Locale.ENGLISH
            tts?.setSpeechRate(0.5f)
            _isTTSInitialized.value = true
        } else {
            _isTTSInitialized.value = false
        }
    }

    fun speakLetter(letter: String) {
        if (_isTTSInitialized.value == true) {
            tts?.speak(letter, TextToSpeech.QUEUE_FLUSH, null, null)
        }
    }

    fun checkAnswer(answerString: String): Boolean {
        return (answerString.lowercase() == currentQuestion.value?.correctAnswer?.correctWord?.lowercase())
    }

    fun observeData() {
        viewModelScope.launch {
            _questionShuffled.collect { newList ->
                var answerString = ""
                newList.forEach { text ->
                    answerString = answerString + text.data
                }
                if (answerString.contains("?") || answerString.isEmpty() || answerString.contains("null")) {
                    println("if-$answerString")
                    _isButtonVisible.value = false
                } else {
                    println("else-$answerString")
                    val checkData = checkAnswer(answerString);
                    if (checkData) {
                        triggerSnackbar("Jawaban Benar")
                        submitAnswer(true)
                        incrementIndexQuiz()
                    } else {
                        submitAnswer(false)
                        triggerSnackbar("Jawaban Salah")
                    }
                    _isButtonVisible.value = true
                }
            }
        }
    }

    private val _snackbarMessage = MutableStateFlow<String?>(null)
    val snackbarMessage: StateFlow<String?> = _snackbarMessage

    fun triggerSnackbar(message: String) {
        _snackbarMessage.value = message
    }

    fun onSnackbarShown() {
        _snackbarMessage.value = null
    }

    override fun onCleared() {
        tts?.stop()
        tts?.shutdown()
        super.onCleared()
    }

    // competition

    private val _totalScore = MutableStateFlow(0)
    val totalScore: StateFlow<Int> get() = _totalScore.asStateFlow()

    private val _scoreReduction = MutableStateFlow(100) // Nilai awal (100)
    val scoreReduction: StateFlow<Int> get() = _scoreReduction.asStateFlow()

    private val _responseTimeMs = MutableStateFlow(0L) // Stopwatch waktu jawaban
    val responseTimeMs: StateFlow<Long> get() = _responseTimeMs.asStateFlow()

    private val _liveCurrentScore = MutableStateFlow(100) // Skor live
    val liveCurrentScore: StateFlow<Int> get() = _liveCurrentScore.asStateFlow()
    private val _formattedResponseTime = MutableStateFlow("0.0")
    val formattedResponseTime: StateFlow<String> get() = _formattedResponseTime.asStateFlow()
    private val _finalScore = MutableStateFlow<Int?>(null) // Menyimpan skor akhir untuk navigasi
    val finalScore: StateFlow<Int?> get() = _finalScore.asStateFlow()

    private var questionList = listOf<MaterialDataModel>()
    private var currentQuestionIndex = 0
    private var wrongAttempts = 0
    private var startTime: Long = 0
    private var isRunning = false

    // Konstanta skor
    private val baseScore = 100
    private val safeTime = 5 // Waktu aman tanpa penalti (detik)
    private val timePenalty = 1 // Penalti per detik setelah safeTime
    private val wrongPenalty = 5 // Penalti per jawaban salah
    private val minScore = 50 // Skor minimum per soal
    private val bonusQuick = 10 // Bonus jika menjawab dalam ≤ 3 detik

    /** Memulai Kuis **/
    fun startQuiz(materials: List<MaterialDataModel>) {
        if (materials.isNotEmpty()) {
            questionList = materials
            currentQuestionIndex = 0
            _totalScore.value = 0
            _scoreReduction.value = baseScore // Reset ke 100
            _responseTimeMs.value = 0
            _liveCurrentScore.value = baseScore
            wrongAttempts = 0
            startTime = System.currentTimeMillis()
            startStopwatch()
        }
    }

    /** Memulai Stopwatch & Update Skor Live **/
    private fun startStopwatch() {
        isRunning = true
        viewModelScope.launch {
            while (isRunning) {
                val elapsedTime = System.currentTimeMillis() - startTime
                _responseTimeMs.value = elapsedTime // Stopwatch berjalan
                _liveCurrentScore.value =
                    calculateRealTimeScore((elapsedTime / 1000).toInt(), wrongAttempts)
                _formattedResponseTime.value = String.format("%.1f", elapsedTime / 1000.0)
                delay(100) // Update setiap 100ms
            }
        }
    }

    /** Saat jawaban dikirim **/
    fun submitAnswer(isCorrect: Boolean) {
        if (isCorrect) {
            isRunning = false // Hentikan stopwatch
            val responseTimeSec = (_responseTimeMs.value / 1000).toInt()
            val finalScore = calculateRealTimeScore(responseTimeSec, wrongAttempts) // Skor final

            _totalScore.value += finalScore // Tambahkan ke total skor
            viewModelScope.launch {
                delay(1000) // Tampilkan skor selama 1 detik sebelum pindah ke soal berikutnya
                moveToNextQuestion()
            }
        } else {
            wrongAnswer()
        }
    }

    /** Saat jawaban salah **/
    fun wrongAnswer() {
        wrongAttempts += 1
        _liveCurrentScore.value =
            calculateRealTimeScore((_responseTimeMs.value / 1000).toInt(), wrongAttempts)
    }

    /** Berganti ke soal berikutnya **/
    private fun moveToNextQuestion() {
        if (currentQuestionIndex < questionList.size - 1) {
            currentQuestionIndex++
            wrongAttempts = 0
            startTime = System.currentTimeMillis()
            _scoreReduction.value = baseScore // Reset ke 100
            _liveCurrentScore.value = baseScore
            startStopwatch() // Restart stopwatch
        } else {
            _finalScore.value = _totalScore.value
        }
    }

    /** Perhitungan Skor Secara Live **/
    private fun calculateRealTimeScore(responseTime: Int, wrongAttempts: Int): Int {
        val penaltyTime = max(0, responseTime - safeTime) * timePenalty
        val penaltyWrong = wrongAttempts * wrongPenalty
        var score = baseScore - penaltyTime - penaltyWrong
        if (responseTime <= 5) {
//            println("responset: $responseTime")
            score += bonusQuick
        }

        return max(minScore, score)
    }
}