package moe.protocol.servlet

import com.tencent.mobileqq.app.QQAppInterface
import moe.fuqiuluo.proto.ProtoUtils
import moe.fuqiuluo.proto.asUtf8String
import moe.fuqiuluo.proto.protobufOf
import moe.fuqiuluo.xposed.tools.slice
import mqq.app.MobileQQ
import mqq.manager.TicketManager
import oicq.wlogin_sdk.request.Ticket
import tencent.im.oidb.oidb_sso

internal object TicketSvc: BaseSvc() {
    object SigType {
        const val WLOGIN_A2 = 64
        const val WLOGIN_A5 = 2
        const val WLOGIN_AQSIG = 2097152
        const val WLOGIN_D2 = 262144
        const val WLOGIN_DA2 = 33554432
        const val WLOGIN_LHSIG = 4194304
        const val WLOGIN_LSKEY = 512
        const val WLOGIN_OPENKEY = 16384
        const val WLOGIN_PAYTOKEN = 8388608
        const val WLOGIN_PF = 16777216
        const val WLOGIN_PSKEY = 1048576
        const val WLOGIN_PT4Token = 134217728
        const val WLOGIN_QRPUSH = 67108864
        const val WLOGIN_RESERVED = 16
        const val WLOGIN_SID = 524288
        const val WLOGIN_SIG64 = 8192
        const val WLOGIN_SKEY = 4096
        const val WLOGIN_ST = 128
        const val WLOGIN_STWEB = 32 // TLV 103
        const val WLOGIN_TOKEN = 32768
        const val WLOGIN_VKEY = 131072
    }

    fun getUin(): String {
        return app.currentUin
    }

    fun getCookie(): String {
        val uin = getUin()
        val skey = getSKey(uin)
        val pskey = getPSKey(uin)
        return "uin=o$uin; skey=$skey; p_uin=o$uin; p_skey=$pskey"
    }

    suspend fun getCookie(domain: String): String {
        val uin = getUin()
        val skey = getSKey(uin)
        val pskey = getPSKey(uin, domain) ?: ""
        val pt4token = getPt4Token(uin, domain) ?: ""
        return "uin=o$uin; skey=$skey; p_uin=o$uin; p_skey=$pskey; pt4_token=$pt4token"
    }

    fun getCSRF(pskey: String = getPSKey(getUin())): String {
        if (pskey.isEmpty()) {
            return "0"
        }
        var v = 5381
        for (element in pskey) {
            v += ((v shl 5) + element.code.toLong()).toInt()
        }
        return (v and Int.MAX_VALUE).toString()
    }

    suspend fun getCSRF(uin: String, domain: String): String {
        var v: Long = 5381
        for (element in getPSKey(uin, domain) ?: "") {
            v += (v shl 5 and 2147483647L) + element.code.toLong()
        }
        return (v and 2147483647L).toString()
    }

    fun getTicket(uin: String, id: Int): Ticket? {
        return (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager).getLocalTicket(uin, id)
    }

    fun getStWeb(uin: String): String {
        return (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager).getStweb(uin)
    }

    fun getSKey(uin: String): String {
        return (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager).getSkey(uin)
    }

    fun getPSKey(uin: String): String {
        val manager = (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager)
        manager.reloadCache(MobileQQ.getContext())
        return manager.getSuperkey(uin) ?: ""
    }

    suspend fun getLessPSKey(domain: String): String? {
        val resp = sendOidbAW("OidbSvcTcp.0x102a", 4138, 0, protobufOf(
            1 to arrayOf(domain),
            //2 to 3
        ).toByteArray()) ?: return null

        val body = oidb_sso.OIDBSSOPkg()
        body.mergeFrom(resp.slice(4))

        return ProtoUtils.decodeFromByteArray(body.bytes_bodybuffer.get().toByteArray())[1][2].asUtf8String
    }

    suspend fun getPSKey(uin: String, domain: String): String? {
        return (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager).getPskey(uin, domain).let {
            if (it.isNullOrBlank()) getLessPSKey(domain) else it
        }
    }

    fun getPt4Token(uin: String, domain: String): String? {
        return (app.getManager(QQAppInterface.TICKET_MANAGER) as TicketManager).getPt4Token(uin, domain)
    }
}