package com.fs.jd.http;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.fs.common.utils.DateUtils;
import com.fs.erp.dto.CommonResponse;
import com.fs.erp.dto.ErpOrderResponseDTO;
import com.fs.erp.utils.SignUtil;
import com.fs.his.config.FsSysConfig;
import com.fs.his.utils.ConfigUtil;
import com.fs.jd.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.fs.common.core.text.CharsetKit.UTF_8;

@Slf4j
@Service
public class JdHttpServiceImpl implements IJdHttpService{

    //正式
    private static final String BASE_URL = "https://api.jdl.com";
    private static final String HEX_CHARACTERS = "0123456789ABCDEF";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final String DELIVERY_CREATE_METHOD = "/integratedsupplychain/order/delivery/create/v1";
    private static final String ORDER_CANCEL_METHOD = "/integratedsupplychain/order/cancel/v1";
    private static final String QUERY_DELIVERY_METHOD = "/integratedsupplychain/order/delivery/query/v1";

    @Autowired
    private ConfigUtil configUtil;

    @Override
    public SoCreateResponseDTO deliveryCreate(SoCreateOrderRequestDTO dto) {
        String method = DELIVERY_CREATE_METHOD;
        String url = BASE_URL + method;
        log.info("京东-销售出库单创建 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
        HttpResponse response;
        try {
            response = executeJsonPost(url, Arrays.asList(dto), method);
        } catch (GeneralSecurityException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return parseResponse(response, new TypeReference<CommonResponse<SoCreateResponseDTO>>() {});
    }

    @Override
    public OrderCancelResponseDTO orderCancel(OrderCancelRequestDTO dto) {
        String method = ORDER_CANCEL_METHOD;
        String url = BASE_URL + method;
        log.info("京东-销售出库单取消 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
        HttpResponse response;
        try {
            response = executeJsonPost(url, Arrays.asList(dto), method);
        } catch (GeneralSecurityException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return parseResponse(response, new TypeReference<CommonResponse<OrderCancelResponseDTO>>() {});
    }

    @Override
    public SoQueryResponseDTO queryDelivery(SoQueryRequestDTO dto) {
        String method = QUERY_DELIVERY_METHOD;
        String url = BASE_URL + method;
        log.info("京东-销售出库单查询 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
        HttpResponse response;
        try {
            response = executeJsonPost(url, Arrays.asList(dto), method);
        } catch (GeneralSecurityException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return parseResponse(response, new TypeReference<CommonResponse<SoQueryResponseDTO>>() {});
    }

    /**
     * 执行JSON格式的POST请求
     *
     * @param url 请求URL
     * @param dto 请求对象
     * @return HttpResponse响应
     */
    private HttpResponse executeJsonPost(String url, Object dto,String method) throws GeneralSecurityException, UnsupportedEncodingException {
        String appKey = "38b123c8d2084beabe21be14549a9749";
        String appSecret = "b088b97cc2924bfc9ec5d09310d17f73";
        String accessToken = "144d2076bf7c4bcdaf1a2c0452eeb021";
//        FsSysConfig sysConfig = configUtil.getSysConfig();
//
//        String appKey = sysConfig.getJdAppKey();
//        String appSecret = sysConfig.getJdAppSecret();
//        String accessToken = sysConfig.getJdAccessToken();

        String algorithm = "md5-salt";
        String domain = "IntegratedSupplyChain";
        String timestamp = DATE_TIME_FORMATTER.format(LocalDateTime.now());
        String jsonBody = JSON.toJSONString(dto);

        log.info("timestamp: {}, jsonBody: {}", timestamp, jsonBody);

        //生成签名字符拼接
        String content = String.join("", new String[]{
                appSecret,
                "access_token", accessToken,
                "app_key", appKey,
                "method", method,
                "param_json", jsonBody,
                "timestamp", timestamp,
                "v", "2.0",
                appSecret});
        String sign = sign(algorithm, content.getBytes(StandardCharsets.UTF_8), appSecret.getBytes(StandardCharsets.UTF_8)).toLowerCase();
        Map<String,String> query  = new HashMap<>();
        query.put("LOP-DN", domain);
        query.put("app_key", appKey);
        query.put("access_token", accessToken);
        query.put("timestamp", timestamp);
        query.put("v", "2.0");
        query.put("sign", URLEncoder.encode(sign, StandardCharsets.UTF_8.toString()));
        String uri = url + "?" + httpBuildQuery(query);
        Map<String, String> headers = MapUtil.builder(new HashMap<String, String>())
                .put("Content-Type", "application/json;charset=utf-8")
                .build();


        log.debug("发送JSON请求 - URL: {}, Headers: {}, Body: {}", uri, headers, jsonBody);

        return HttpRequest.post(uri)
                .headerMap(headers, true)
                .body(jsonBody)
                .execute();
    }

    /**
     * 解析带有泛型的HTTP响应
     *
     * @param response HTTP响应
     * @param typeReference 响应类型引用
     * @param <T> 期望的响应数据类型
     * @return 解析后的数据
     */
    private <T> T parseResponse(HttpResponse response, TypeReference<CommonResponse<T>> typeReference) {
        String body = response.body();
        log.debug("解析响应体: {}", body);


        CommonResponse<T> commonResponse = JSON.parseObject(body, typeReference);

        if (!Integer.valueOf(1000).equals(commonResponse.getCode())) {
            log.error("API请求失败 - 错误码: {}, 错误信息: {}", commonResponse.getCode(), commonResponse.getMessage());
            throw new RuntimeException("请求接口失败！原因：" + commonResponse.getMessage());
        }
        log.info("response: {}", commonResponse);
        T result = commonResponse.getData();
        log.info("API请求成功 - 结果: {}", JSON.toJSONString(result));
        return result;
    }

    private static String httpBuildQuery(Map<String, String> query) throws UnsupportedEncodingException {
        StringBuilder stringBuilder = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : query.entrySet()) {
            if (!first) {
                stringBuilder.append("&");
            } else {
                first = false;
            }
            stringBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), UTF_8));
        }
        return stringBuilder.toString();
    }

    private  String sign(String algorithm, byte[] data, byte[] secret) throws GeneralSecurityException {
        if (Objects.equals(algorithm, "md5-salt")) {
            return bytesToHex(MessageDigest.getInstance("md5").digest(data));
        } else if (Objects.equals(algorithm, "HMacMD5")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA1")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA256")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA512")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        }
        throw new GeneralSecurityException("Algorithm " + algorithm + " not supported yet");
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            stringBuilder.append(HEX_CHARACTERS.charAt((b >>> 4) & 0x0F));
            stringBuilder.append(HEX_CHARACTERS.charAt(b & 0x0F));
        }
        return stringBuilder.toString();
    }
}
