package com.xyzshell.andinfo.utils

import android.util.Base64
import com.google.gson.Gson
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

/**
 * 设备信息上传 API 地址
 */
const val upload_info_api = "https://api.xyzshell.com/api/mobile/checker/save"

/**
 * Web 服务工具类
 * 提供 HTTP 请求、JSON 序列化和 AES 加密功能
 */
class WebService {
    /**
     * OkHttp 客户端实例
     */
    private val client = OkHttpClient()

    /**
     * Gson 序列化工具
     */
    val gson = Gson()

    /**
     * AES 加密密钥（必须是 16/24/32 字节）
     */
    private val aesKey = "e67cbcee5e573d1b"

    /**
     * AES 加密方法
     * 使用 AES/ECB 模式加密字符串
     *
     * @param plainText 明文字符串
     * @return Base64 编码的加密字符串
     * @throws Exception 加密失败时抛出异常
     */
    fun encrypt(plainText: String): String {
        return try {
            val secretKey = SecretKeySpec(aesKey.toByteArray(), "AES")
            val cipher = Cipher.getInstance("AES")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)
            val encryptedBytes = cipher.doFinal(plainText.toByteArray())
            Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
        } catch (e: Exception) {
            throw Exception("加密失败: ${e.message}")
        }
    }

    /**
     * 异步 POST 请求
     *
     * @param url 请求地址
     * @param jsonData JSON 格式的请求数据
     * @param callback 回调函数 (响应字符串, 错误异常)
     */
    fun postData(url: String, jsonData: String, callback: (String?, Exception?) -> Unit) {
        val mediaType = "application/json; charset=utf-8".toMediaType()
        val body = jsonData.toRequestBody(mediaType)

        val request = Request.Builder()
            .url(url)
            .post(body)
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback(null, e)
            }

            override fun onResponse(call: Call, response: Response) {
                response.use {
                    if (it.isSuccessful) {
                        callback(it.body?.string(), null)
                    } else {
                        callback(null, Exception("HTTP ${it.code}"))
                    }
                }
            }
        })
    }

    /**
     * 同步 POST 请求（阻塞当前线程）
     *
     * @param url 请求地址
     * @param jsonData JSON 格式的请求数据
     * @return 响应字符串，失败时返回 null
     */
    fun postDataSync(url: String, jsonData: String): String? {
        val mediaType = "application/json; charset=utf-8".toMediaType()
        val body = jsonData.toRequestBody(mediaType)

        val request = Request.Builder()
            .url(url)
            .post(body)
            .build()

        client.newCall(request).execute().use { response ->
            return if (response.isSuccessful) {
                response.body?.string()
            } else {
                null
            }
        }
    }

    /**
     * 序列化对象为 JSON 字符串
     *
     * @param obj 要序列化的对象
     * @return JSON 字符串
     */
    fun <T> toJson(obj: T): String {
        return gson.toJson(obj)
    }

    /**
     * 反序列化 JSON 字符串为对象
     *
     * @param json JSON 字符串
     * @return 反序列化的对象，失败时返回 null
     */
    inline fun <reified T> fromJson(json: String): T? {
        return try {
            gson.fromJson(json, T::class.java)
        } catch (e: Exception) {
            null
        }
    }

    /**
     * 带序列化的 POST 请求
     * 自动将对象序列化为 JSON 后发送
     *
     * @param url 请求地址
     * @param obj 要发送的对象
     * @param callback 回调函数 (响应字符串, 错误异常)
     */
    fun <T> postObject(url: String, obj: T, callback: (String?, Exception?) -> Unit) {
        val jsonData = toJson(obj)
        postData(url, jsonData, callback)
    }

    /**
     * 带序列化和反序列化的 POST 请求
     * 自动将请求对象序列化为 JSON，并将响应反序列化为对象
     *
     * @param url 请求地址
     * @param obj 要发送的对象
     * @param callback 回调函数 (响应对象, 错误异常)
     */
    inline fun <reified T, reified R> postAndParse(
        url: String,
        obj: T,
        crossinline callback: (R?, Exception?) -> Unit
    ) {
        val jsonData = toJson(obj)
        postData(url, jsonData) { response, error ->
            if (error != null) {
                callback(null, error)
            } else if (response != null) {
                val result = fromJson<R>(response)
                callback(result, null)
            } else {
                callback(null, Exception("Empty response"))
            }
        }
    }
}