package org.jeecg.module.custom.ocr.common.entity;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.jeecg.module.custom.ocr.utils.ApiHelper;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * <ol>
 * <li>
 * GET/DELETE请求：Query String
 * 参考：{@link }
 * </li>
 * <li>
 * POST/PATCH/PUT请求：JSON格式请求体
 * <pre>
 *   {
 *    "tenantCode": “syxy”,
 *    "accessKey": "syncuser",
 *    "data": {
 *      // 加密的业务数据
 *    },
 *    "timestamp": 1689837406368,
 *    "signature": "eUk5kY-xR6XMjzjJRrl2T3EE_c5wztJNvdNWEY3vxfo"
 *   }
 * </pre>
 * 参考：{@link #toString()}
 * </li>
 * </ol>
 * @author hdzhong
 * @date 2023/9/20
 */
@Data
@ApiModel(value = "请求统一Query/JSON封装",description = "接口统一请求报文")
public class RequestData implements Serializable {
    public final static String TIMESTAMP = "_timestamp";
    public final static String SIGNATURE = "_signature";

    /**
     * URL的Query参数
     */
    @ApiModelProperty(value = "Query参数")
    private Map<String, String> parameters;
    /**
     * 租户代码
     */
    @ApiModelProperty(value = "租户代码")
    private String tenantCode;
    /**
     * 访问标识
     */
    @ApiModelProperty(value = "访问标识")
    private String accessKey;
    /**
     * 进行加密后的业务数据
     * @see ApiHelper#encrypt(String, String, String)
     */
    @ApiModelProperty(value = "加密的请求数据")
    private String data;
    /**
     * 请求时间戳，作为签名、加密的随机盐（Salt）
     * @see ApiHelper#combineSalt(String, String)
     */
    @ApiModelProperty(value = "请求时间戳")
    private long timestamp ;
    /**
     * 数据签名
     * @see ApiHelper#getSignature(String, String, Map)
     */
    @ApiModelProperty(value = "数据签名")
    private String signature;

    /**
     * <pre>
     * {
     *  "tenantCode": “syxy”,
     *  "accessKey": "syncuser",
     *  "data": {
     *    // 加密的业务数据
     *  },
     *  "timestamp": 1689837406368,
     *  "signature": "eUk5kY-xR6XMjzjJRrl2T3EE_c5wztJNvdNWEY3vxfo"
     * }
     * </pre>
     * @return JSON string
     */
    @Override
    public String toString() {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> map = new LinkedHashMap<>();
        // tenant code
        map.put("tenantCode", tenantCode);
        // access key
        map.put("accessKey", accessKey);
        // data
        map.put("data", data);
        // timestamp
        map.put("timestamp", timestamp);
        // signature
        map.put("signature", signature);

        // return json
        try {
            return objectMapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * add tenantCode, accessKey, {@link  #TIMESTAMP}, {@link  #SIGNATURE} to parameters
     *
     * @return new query parameters
     */
    public Map<String, String> toQueryParameters() {
        Map<String, String> map = new LinkedHashMap<>();
        // put parameters
        map.putAll(parameters);
        // append tenant code
        map.put("tenantCode", tenantCode);
        // append access key
        map.put("accessKey", accessKey);
        // append timestamp & signature
        map.put(TIMESTAMP, String.valueOf(timestamp));
        map.put(SIGNATURE, signature);

        // return query parameters
        return map;
    }

    /**
     * combine parameters to query string
     * @return query string
     * @see #toQueryParameters()
     */
    public String toQuery() {
        // return query parameters
        return buildQuery(toQueryParameters());
    }

    /**
     * convert parameters to query string
     *
     * @param parameters query parameters
     * @return query string kye1=value1&key2=value2
     */
    public static final String buildQuery(Map<String, String> parameters) {
        final StringBuilder builder = new StringBuilder();
        parameters.forEach((k, v) -> {
            if (StringUtils.isEmpty(k)) {
                return;
            }

            if (builder.length() > 0) {
                builder.append('&');
            }
            try {
                builder.append(URLEncoder.encode(k, StandardCharsets.UTF_8.name()))
                        .append('=')
                        .append(v == null ? "" : URLEncoder.encode(v, StandardCharsets.UTF_8.name()));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        });
        return builder.toString();
    }
}
