package com.atmob.keyboard_android.mvvm.viewmodel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.atmob.keyboard_android.enums.HelpMode
import com.atmob.keyboard_android.enums.KeyboardGlobalType
import com.atmob.keyboard_android.enums.KeyboardType
import com.atmob.keyboard_android.mvvm.base.BaseViewModel
import com.atmob.keyboard_android.mvvm.repository.KeyboardRepository
import com.atmob.keyboard_android.util.LogUtil
import com.atmob.keyboard_android.util.bridge.model.base.EmptyResp
import com.atmob.keyboard_android.util.bridge.model.req.SuperReplyReq
import com.atmob.keyboard_android.util.bridge.model.req.SuperSpeakReq
import com.atmob.keyboard_android.util.bridge.model.resp.CharacterListResp.CharacterInfo
import com.atmob.keyboard_android.util.bridge.model.resp.KeyboardInfo
import com.atmob.keyboard_android.util.bridge.model.resp.PrologueListResp.PrologueListItem
import com.atmob.keyboard_android.util.bridge.model.resp.PrologueListResp.Topic
import com.atmob.keyboard_android.util.error.ErrorHandler

/**
 * 键盘ViewModel
 */
class KeyboardViewModel : BaseViewModel() {
    /**
     * 仓库层
     */
    private val mKeyboardRepository = KeyboardRepository()

    // ----------------------------------- 响应式变量 -----------------------------------

    /**
     * 登录页，是否展示
     */
    private val _loginPageShowing = MutableLiveData(false)
    val loginPageShowing: LiveData<Boolean> = _loginPageShowing

    /**
     * 设置页，是否展示
     */
    private val _settingPageShowing = MutableLiveData(false)
    val settingPageShowing: LiveData<Boolean> = _settingPageShowing

    /**
     * VIP页，是否显示
     */
    private val _vipPageShowing = MutableLiveData(false)
    val vipPageShowing: LiveData<Boolean> = _vipPageShowing

    /**
     * 键盘选择页，是否显示
     */
    private val _keyboardSelectPageShowing = MutableLiveData(false)
    val keyboardSelectPageShowing: LiveData<Boolean> = _keyboardSelectPageShowing

    /**
     * 超会说-Ai生成内容页，是否显示
     */
    private val _superSpeakAiChatPageShowing = MutableLiveData(false)
    val superSpeakAiChatPageShowing: LiveData<Boolean> = _superSpeakAiChatPageShowing

    /**
     * 开场白-Ai生成内容页，是否显示
     */
    private val _prologueAiChatPageShowing = MutableLiveData(false)
    val prologueAiChatPageShowing: LiveData<Boolean> = _prologueAiChatPageShowing

    /**
     * 帮助模式，帮聊、教你说、开场白等
     */
    private val _helpMode = MutableLiveData(HelpMode.HELP_CHAT)
    val helpMode: LiveData<HelpMode> = _helpMode

    /**
     * 全局键盘类型
     */
    private val _keyboardGlobalType = MutableLiveData(KeyboardGlobalType.AI_KEYBOARD)
    val keyboardGlobalType: LiveData<KeyboardGlobalType> = _keyboardGlobalType

    /**
     * 当前键盘信息
     */
    private val _currentKeyboardInfo = MutableLiveData<KeyboardInfo>()
    val currentKeyboardInfo: LiveData<KeyboardInfo> = _currentKeyboardInfo

    /**
     * 当前选中的开场白Tab
     */
    private val _currentPrologueTab = MutableLiveData<String>()
    val currentPrologueTab: LiveData<String> = _currentPrologueTab

    /**
     * 人设列表
     */
    private val _characterList = MutableLiveData<List<CharacterInfo>>()
    val characterList: LiveData<List<CharacterInfo>> = _characterList

    /**
     * 开场白列表
     */
    private val _prologueList =
        MutableLiveData<List<PrologueListItem>>()
    val prologueList: LiveData<List<PrologueListItem>> = _prologueList

    /**
     * AI聊天-超会回（帮聊）结果
     */
    private val _chatSuperReplyResult = MutableLiveData<String>()
    val chatSuperReplyResult: LiveData<String> = _chatSuperReplyResult

    /**
     * AI聊天-超会说（教你说）结果
     */
    private val _superSpeakChatListResult = MutableLiveData<List<String>>()
    val superSpeakChatListResult: LiveData<List<String>> = _superSpeakChatListResult

    /**
     * AI聊天-开场白结果
     */
    private val _prologueChatListResult = MutableLiveData<List<String>>()
    val prologueChatListResult: LiveData<List<String>> = _prologueChatListResult

    /**
     * 用户的剪切板数据
     */
    private val _userClipboardData = MutableLiveData("")
    val userClipboardData: LiveData<String> = _userClipboardData

    /**
     * 键盘选择列表数据
     */
    private val _keyboardList = MutableLiveData<List<KeyboardInfo>>()
    val keyboardList: LiveData<List<KeyboardInfo>> = _keyboardList

    // ----------------------------------- 更新状态方法 -----------------------------------

    /**
     * 更新，登录页，是否显示
     */
    fun updateLoginPageShowing(isShowing: Boolean) {
        _loginPageShowing.value = isShowing
    }

    /**
     * 更新，设置页，是否显示
     */
    fun updateSettingPageShowing(isShowing: Boolean) {
        _settingPageShowing.value = isShowing
    }

    /**
     * 更新，键盘选择页，是否显示
     */
    fun updateKeyboardSelectPageShowing(isShowing: Boolean) {
        _keyboardSelectPageShowing.value = isShowing
    }

    /**
     * 更新，VIP页，是否显示
     */
    fun updateVipPageShowing(isShowing: Boolean) {
        _vipPageShowing.value = isShowing
    }

    /**
     * 更新，超会说-Ai生成内容页，是否显示
     */
    fun updateSuperSpeakAiChatPageShowing(isShowing: Boolean) {
        _superSpeakAiChatPageShowing.value = isShowing
    }

    /**
     * 更新，开场白-Ai生成内容页，是否显示
     */
    fun updatePrologueAiChatPageShowing(isShowing: Boolean) {
        _prologueAiChatPageShowing.value = isShowing
    }

    /**
     * 更新帮助模式
     */
    fun updateHelpMode(newMode: HelpMode) {
        _helpMode.value = newMode
    }

    /**
     * 更新全局键盘类型
     */
    fun updateKeyboardGlobalType(keyboardGlobalType: KeyboardGlobalType) {
        this._keyboardGlobalType.value = keyboardGlobalType
    }

    /**
     * 更新当前选中的开场白的Tab
     */
    fun updateCurrentPrologueTab(tab: String) {
        _currentPrologueTab.value = tab
    }

    /**
     * 更新，用户的剪切板数据
     */
    fun updateUserClipboardData(newText: String) {
        _userClipboardData.value = newText
    }

    // ----------------------------------- 获取业务数据方法 -----------------------------------

    /**
     * 用户是否已登录
     */
    fun isLogin(
        onSuccess: (resultObj: Boolean) -> Unit
    ) {
        mKeyboardRepository.isLogin(
            onSuccess,
            onFail = { errorCode, errorMsg ->
                ErrorHandler.handleError(errorCode, errorMsg)
            })
    }

    /**
     * 用户是否为VIP
     */
    fun isMember(
        onSuccess: (resultObj: Boolean) -> Unit
    ) {
        mKeyboardRepository.isMember(onSuccess, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
        })
    }

    /**
     * 获取键盘列表
     */
    fun getKeyboardList() {
        mKeyboardRepository.getKeyboardList(onSuccess = {
            val infos = it.keyboardInfos
            val keyboardList = infos.map {
                fixKeyboardSelectField(it)
            }.toList()
            // 如果所有都没选中，则默认选中通用键盘
            val hasSelectKeyboard = keyboardList.filter {
                it.isSelect == true
            }.toList().isNotEmpty()
            if (!hasSelectKeyboard) {
                // 找到系统键盘
                val systemKeyboard = infos.filter {
                    KeyboardType.isSystem(it.type ?: "")
                }.toList()
                // 勾选默认键盘
                if (systemKeyboard.isNotEmpty()) {
                    systemKeyboard.first().isSelect = true
                }
            }
            _keyboardList.value = infos
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
        })
    }

    /**
     * 更新当前键盘信息
     */
    fun updateCurrentKeyboardInfo(keyboardInfo: KeyboardInfo) {
        _currentKeyboardInfo.value = keyboardInfo
    }

    /**
     * 选择键盘
     *
     * @param selectModel 键盘选择信息
     */
    fun selectedKeyboard(
        selectModel: KeyboardInfo,
        onSuccess: (resultObj: EmptyResp) -> Unit
    ) {
        mKeyboardRepository.selectedKeyboard(selectModel.id!!, onSuccess = {
            // 更新键盘信息
            _currentKeyboardInfo.value = selectModel
            onSuccess.invoke(it)
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
        })
    }

    /**
     * 获取当前键盘信息
     */
    fun getCurrentKeyboardInfo() {
        getCurrentKeyboardInfoWithDefault(onSuccess = {
            _currentKeyboardInfo.value = fixKeyboardSelectField(it)
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
        })
    }

    /**
     * 获取人设列表
     */
    fun getCharacterList() {
        val errorCallback = { errorCode: Int, errorMsg: String ->
            ErrorHandler.handleError(errorCode, errorMsg)
        }
        // 先获取当前键盘信息，得到键盘Id
        getCurrentKeyboardInfoWithDefault(onSuccess = { keyboardInfo ->
            val keyboardId = keyboardInfo.id!!
            val keyboardName = keyboardInfo.name
            LogUtil.d("加载人设列表, id: ${keyboardId}, name: $keyboardName")
            // 查询该键盘下的人设列表
            mKeyboardRepository.getCharacterList(keyboardId, onSuccess = {
                _characterList.value = it.characterInfos ?: listOf()
            }, errorCallback)
        }, onFail = errorCallback)
    }

    /**
     * 获取开场白列表
     */
    fun getPrologueList() {
        mKeyboardRepository.getPrologueList(onSuccess = {
            _prologueList.value = it.prologues ?: listOf()
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
        })
    }

    /**
     * 过滤出对应Tab的开场白列表
     *
     * @param tab 选择的Tab类型
     */
    fun filterPrologueListByTab(tab: String): List<Topic> {
        // 按照选择Tab，过滤出对应Tab的开场白数据
        val tabPrologues = _prologueList.value?.firstOrNull {
            it.title == tab
        }
        // 该Tab下的开场白列表
        return tabPrologues?.topics ?: listOf()
    }

    /**
     * AI聊天-超会回（帮聊）
     *
     * @param characterId 人设Id
     */
    fun chatSuperReply(
        characterId: String,
        onSuccess: () -> Unit,
        onFail: (String) -> Unit
    ) {
        val req = SuperReplyReq(
            // 键盘Id
            keyboardId = _currentKeyboardInfo.value?.id ?: "",
            // 人设Id
            characterId = characterId,
            // 用户粘贴板中的内容
            content = _userClipboardData.value ?: ""
        )
        _chatSuperReplyResult.value = ""
        mKeyboardRepository.chatSuperReply(req, onSuccess = {
            // 只有一条数据，直接添加到输入框
            _chatSuperReplyResult.value = it.content
            onSuccess.invoke()
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
            onFail.invoke(errorMsg)
        })
    }

    /**
     * AI聊天-超会说（教你说）
     *
     * @param characterId 人设Id
     */
    fun chatSuperSpeak(
        characterId: String,
        onStart: () -> Unit,
        onSuccess: () -> Unit,
        onFail: (String) -> Unit
    ) {
        onStart.invoke()
        _superSpeakChatListResult.value = listOf<String>()
        val req = SuperSpeakReq(
            // 键盘Id
            keyboardId = _currentKeyboardInfo.value?.id ?: "",
            // 人设Id
            characterId = characterId,
            // 用户粘贴板中的内容
            content = _userClipboardData.value ?: ""
        )
        mKeyboardRepository.chatSuperSpeak(req, onSuccess = {
            // 有多条数据，需要跳转列表页面中显示
            _superSpeakChatListResult.value = it.list
            onSuccess.invoke()
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
            onFail.invoke(errorMsg)
        })
    }

    /**
     * AI聊天-开场白
     */
    fun chatPrologue(
        name: String,
        onStart: () -> Unit,
        onSuccess: () -> Unit,
        onFail: (String) -> Unit
    ) {
        onStart.invoke()
        _prologueChatListResult.value = listOf<String>()
        mKeyboardRepository.chatPrologue(name, onSuccess = {
            // 有多条数据，需要跳转列表页面中显示
            _prologueChatListResult.value = it.list
            onSuccess.invoke()
        }, onFail = { errorCode, errorMsg ->
            ErrorHandler.handleError(errorCode, errorMsg)
            onFail.invoke(errorMsg)
        })
    }

    /**
     * 获取键盘信息，如果没有，则返回第一个键盘信息
     */
    fun getCurrentKeyboardInfoWithDefault(
        onSuccess: (model: KeyboardInfo) -> Unit,
        onFail: (errorCode: Int, errorMsg: String) -> Unit
    ) {
        mKeyboardRepository.getCurrentKeyboardInfo(onSuccess = {
            // 如果当前未在键盘中，手动选择过，就会为null
            if (it.id.isNullOrBlank()) {
                mKeyboardRepository.getKeyboardList(onSuccess = {
                    val infos = it.keyboardInfos.map {
                        fixKeyboardSelectField(it)
                    }
                    // 数据为空
                    if (infos.isEmpty()) {
                        onFail.invoke(-1, "")
                    } else {
                        // 先找已选中的键盘，否则找系统键盘
                        val selectedKeyboard = infos.filter {
                            it.isSelect == true
                        }.toList().firstOrNull()
                        if (selectedKeyboard != null) {
                            onSuccess.invoke(selectedKeyboard)
                        } else {
                            // 没有找到选中的键盘，则使用系统键盘
                            val systemKeyboard = infos.filter {
                                KeyboardType.isSystem(it.type ?: "")
                            }.toList()
                            if (systemKeyboard.isNotEmpty()) {
                                onSuccess.invoke(systemKeyboard.first())
                            } else {
                                // 连系统键盘都没有，则取第一个
                                onSuccess.invoke(infos[0])
                            }
                        }
                    }
                }, onFail)
            } else {
                onSuccess.invoke(fixKeyboardSelectField(it))
            }
        }, onFail)
    }

    /**
     * 处理isSelect字段
     */
    private fun fixKeyboardSelectField(info: KeyboardInfo): KeyboardInfo {
        // 统一使用isSelect字段，优先使用isSelect字段，代表是用户手动在键盘中操作过的，否则就用isChoose，是其他页面中选择过的
        info.isSelect = if (info.isSelect != null) {
            info.isSelect == true
        } else {
            info.isChoose == true
        }
        return info
    }
}