package com.jihe.punchnet.api

import com.google.gson.GsonBuilder
import com.google.gson.JsonParser
import okhttp3.Interceptor
import okhttp3.Response
import okio.Buffer
import java.nio.charset.StandardCharsets
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

class SignInterceptor : Interceptor {

    private val secretKey = "H6p*2RfEu4ITcL"

    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val body = originalRequest.body

        if (originalRequest.method == "POST" && body != null && body.contentType()?.subtype == "json") {
            try {
                // Read original JSON body
                val buffer = Buffer()
                body.writeTo(buffer)
                val jsonStr = buffer.readUtf8()

                // Parse into JsonObject
                val jsonElement = JsonParser.parseString(jsonStr)
                if (jsonElement.isJsonObject) {
                    val jsonObject = jsonElement.asJsonObject
                    
                    // Sort keys
                    val sortedKeys = jsonObject.keySet().sorted()

                    // Build query string
                    val queryStringBuilder = StringBuilder()
                    val gson = GsonBuilder().disableHtmlEscaping().create()

                    for (key in sortedKeys) {
                        val element = jsonObject.get(key)
                        if (element.isJsonNull) continue

                        if (queryStringBuilder.isNotEmpty()) {
                            queryStringBuilder.append("&")
                        }
                        
                        queryStringBuilder.append(key).append("=")

                        if (element.isJsonPrimitive) {
                            val primitive = element.asJsonPrimitive
                            if (primitive.isString) {
                                queryStringBuilder.append(primitive.asString)
                            } else {
                                // numbers and booleans
                                queryStringBuilder.append(primitive.asString)
                            }
                        } else {
                            // Object or Array - convert to JSON string (JSON_UNESCAPED_UNICODE is default in Gson if disableHtmlEscaping is used)
                            queryStringBuilder.append(gson.toJson(element))
                        }
                    }

                    val queryString = queryStringBuilder.toString()
                    
                    // Calculate HMAC-MD5
                    val sign = calculateHmacMD5(queryString, secretKey)
                    // Inject sign into HTTP Header X-sign
                    val newRequest = originalRequest.newBuilder()
                        .addHeader("X-sign", sign)
                        .post(body)
                        .build()

                    return chain.proceed(newRequest)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        return chain.proceed(originalRequest)
    }

    private fun calculateHmacMD5(data: String, key: String): String {
        val algorithm = "HmacMD5"
        val mac = Mac.getInstance(algorithm)
        val secretKeySpec = SecretKeySpec(key.toByteArray(StandardCharsets.UTF_8), algorithm)
        mac.init(secretKeySpec)
        val hashBytes = mac.doFinal(data.toByteArray(StandardCharsets.UTF_8))
        return hashBytes.joinToString("") { "%02x".format(it) }
    }
}
