package com.iscs.bozzys.ui.pages.vm

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.viewModelScope
import com.iscs.bozzys.R
import com.iscs.bozzys.api.ApiRequest
import com.iscs.bozzys.api.ApiRequest.getResponse
import com.iscs.bozzys.ui.common.VMBase
import com.iscs.bozzys.utils.BiometricKeyStore
import com.iscs.bozzys.utils.Storage
import com.iscs.bozzys.utils.Storage.saveRefreshToken
import com.iscs.bozzys.utils.Storage.saveTenantId
import com.iscs.bozzys.utils.Storage.saveToken
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

/**
 * 登录ViewModel层
 */
class VMLogin : VMBase() {

    var state by mutableStateOf(StateLogin())
        private set

    // 是否登录成功
    private var isLogin = false

    /**
     * 检查租户ID是否显示
     */
    fun init() {
        val tenantId = Storage.readTenantId()
        state = state.copy(showTenantId = tenantId.isEmpty(), tenantId = tenantId)
    }

    /**
     * 更新登录方式
     *
     * @param type 0:短信验证码登录 1:账号密码登录
     */
    fun updateLoginType(type: Int) {
        state = state.copy(loginType = type)
    }

    /**
     * 更新账号字段数据
     *
     * @param account loginType=0时为手机号 loginType=1时为用户名
     */
    fun updateAccount(account: String) {
        state = state.copy(account = account)
    }

    /**
     * 更新code字段
     *
     * @param code loginType=0时为验证码 loginType=1时为密码
     */
    fun updateCode(code: String) {
        state = state.copy(code = code)
    }

    /**
     * 执行登录操作
     */
    fun login(done: () -> Unit) {
        if (isLogin) return
        viewModelScope.launch {
            val check = checkCanLogin()
            if (check != 0) {
                toast.emit(check)
                return@launch
            }
            state.tenantId.saveTenantId()
            loading.emit(StateLoading(show = true))
            ApiRequest.login(state.account, state.code).onSuccess {
                isLogin = true
                it.data?.accessToken.saveToken()
                it.data?.refreshToken.saveRefreshToken()
                Storage.saveLogin(true)
                loading.emit(StateLoading(show = false))
                toast.emit("登录成功")
                delay(500)
                done.invoke()
            }.onFailure {
                isLogin = false
                delay(500)
                loading.emit(StateLoading(show = false))
                toast.emit(it.getResponse<Any>().msg)
            }
        }
    }

    fun showInputDialog() {
        viewModelScope.launch {
            // 增加视觉停留效果
            delay(500)
            state = state.copy(showInputDialog = true)
        }
    }

    fun updateInputValue(value: String) {
        state = state.copy(tenantId = value)
    }

    fun hideInputDialog() {
        state = state.copy(showInputDialog = false)
    }

    /**
     * 存储登录成功后生成的签名向量
     *
     * @param token
     */
    fun encryptAndSaveToken(token: String) {
        BiometricKeyStore.createKeyIfNeeded()
        val cipher = BiometricKeyStore.encryptCipher()
        val encrypted = cipher.doFinal(token.toByteArray())
        // 保存 encrypted + cipher.iv
        // (encrypted + cipher.iv).saveTokenIv()
    }

    /**
     * 检验是否可以提交登录
     */
    private fun checkCanLogin(): Int {
        if (state.loginType == 0) {
            if (state.account.trim().isEmpty()) return R.string.input_phone_number_tips
            if (state.code.trim().isEmpty()) return R.string.input_code_tips
        } else if (state.loginType == 1) {
            if (state.account.trim().isEmpty()) return R.string.input_account_tips
            if (state.code.trim().isEmpty()) return R.string.input_pwd_tips
        }
        if (state.tenantId.isEmpty()) return R.string.input_tenant_id_tips
        return 0
    }

}

/**
 * 登录页面状态模型
 *
 * @param showTenantId 是否显示租户配置
 * @param showInputDialog   是否显示输入框
 * @param tenantId          用户输入的租户ID
 */
data class StateLogin(
    val loginType: Int = 1,
    val account: String = "",
    val code: String = "",
    val showTenantId: Boolean = false,
    val showInputDialog: Boolean = false,
    val tenantId: String = ""
)