/*
 * Copyright (c) 2025 SimcuTeam. All rights reserved.
 * 遵循 MIT 许可证。
 */

package simcu::simapi.helpers

import std.collection.*
import std.io.*
import simcu::serialization.*
import soulsoft_web_http.*
import simcu::simapi.communications.*
import simcu::simapi.exceptions.*
import simcu::simapi.interfaces.*

/**
 * AES body 请求（{"data": "密文"}）。
 */
public class AesBodyRequest {
    public var data: String = ""
}

/**
 * 服务端 AES body 解密校验器。
 *
 * 仓颉无 ModelBinder 机制，按项目惯例由控制器在方法开头调用：
 *   let jsonStr = SimApiAesBodyChecker.decryptBody(context, provider)
 *   let request = JsonSerializer.deserialize<XxxRequest>(jsonStr)
 * 或标注 @AesBody 注解自动执行（SimApiRequestDelegateFactory）。
 *
 * 流程：
 *   1. 读取 body 并反序列化为 {"data": "密文"}
 *   2. 校验 Data 非空
 *   3. 提取 appId（Query/Header）
 *   4. provider.getKey(appId) 获取密钥
 *   5. SimApiAesUtil.decrypt 解密得到明文 JSON 字符串
 * 返回解密后的 JSON 字符串，由控制器按目标类型反序列化。
 */
public class SimApiAesBodyChecker {
    private init() {}

    /**
     * 解密请求体，返回明文 JSON 字符串。
     * @param context 当前请求上下文。
     * @param provider AES 密钥提供器。
     * @return 解密后的 JSON 字符串。
     */
    public static func decryptBody(context: HttpContext, provider: AesBodyProviderBase): String {
        // 1. 读取 body
        let body = readBody(context)
        if (body.isEmpty()) {
            SimApiError.error(code: 400, message: "请求体不能为空")
        }

        // 2. 反序列化 {"data": "密文"}
        let req = JsonSerializer.deserialize<AesBodyRequest>(body)
        if (req.data.isEmpty()) {
            SimApiError.error(code: 400, message: "请求体缺少密文Data字段")
        }

        // 3. 提取 appId
        var appId: ?String = None
        if (let Some(name) <- provider.appIdName) {
            if (!name.isEmpty()) {
                appId = getParam(context, name)
                if (appId == None || appId == Some("")) {
                    SimApiError.error(code: 400, message: "未找到${name}")
                }
            }
        }

        // 4. 获取密钥
        let key = provider.getKey(appId)
        if (key == None || key == Some("")) {
            SimApiError.error(code: 400, message: "获取密钥失败（应用不存在或密钥未配置）")
        }

        // 5. 解密
        let jsonStr = SimApiAesUtil.decrypt(req.data, key.getOrThrow())
        if (jsonStr.isEmpty()) {
            SimApiError.error(code: 400, message: "解密失败")
        }
        jsonStr
    }

    private static func readBody(context: HttpContext): String {
        try {
            context.request.enableBuffering()
            var buffer = Array<Byte>(4096, repeat: 0)
            var sb = StringBuilder()
            var read = context.request.body.read(buffer)
            while (read > 0) {
                sb.appendFromUtf8(buffer.slice(0, read))
                read = context.request.body.read(buffer)
            }
            // 重置流位置，供后续业务读取
            if (let seekable: Seekable <- context.request.body) {
                seekable.seek(SeekPosition.Begin(0))
            }
            sb.toString()
        } catch (ex: Exception) {
            SimApiError.error(code: 400, message: "读取请求体失败: ${ex.message}")
        }
        ""
    }

    private static func getParam(context: HttpContext, name: String): ?String {
        let q = context.request.query.get(name)
        if (q != None && q != Some("")) {
            return q
        }
        context.request.headers.get(name)
    }
}
