package com.cool.store.http;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.RedisConstant;
import com.cool.store.dao.ShopInfoDAO;
import com.cool.store.dao.StoreDao;
import com.cool.store.entity.StoreDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.RsaSignUtil;
import com.cool.store.utils.StringUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.catalina.Store;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author suzhuhong
 * @Date 2025/11/13 10:00
 * @Version 1.0
 */
@Service
@Slf4j
public class WalletHttpClientRest {

    @Autowired
    private OkHttpClient okHttpClient;

    @Autowired
    private ObjectMapper objectMapper;

    @Resource
    RedisUtilPool redisUtilPool;

    private static final String STORE_ID = "outStoreId";

    @Value("${cool.api.rsa.private.key}")
    private String coolPrivateKey;
    @Value("${wallet.api.rsa.public.key}")
    private String walletPublicKey;
    @Value("${wallet.api.yzt.key}")
    private String yztKey;


    /**
     * 发送带签名的POST请求
     */
    public <T> T postWithSign(String url, Object request, Class<T> responseType) {
        try {
            // 1. 准备请求参数
            Map<String, Object> requestParams = convertToMap(request);
            requestParams.put("timestamp", System.currentTimeMillis());
            requestParams.put("key", yztKey);
            // 2. 生成签名
            String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
            requestParams.put("sign", signature);

            // 3. 发送请求
            String responseJson = executePost(url, requestParams);

            // 4. 解析响应
            return parseResponse(responseJson, responseType);

        }  catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            // 其他异常统一包装为RuntimeException
            log.error("发送带签名POST请求失败: {}", url, e);
            throw new RuntimeException("接口调用异常: " + e.getMessage(), e);
        }
    }

    /**
     * 发送带签名和验签的POST请求
     */
    public <T> T postWithSignAndVerify(String url, Object request, Class<T> responseType) {
        try {
            // 1. 准备请求参数
            Map<String, Object> requestParams = convertToMap(request);
            requestParams.put("timestamp", System.currentTimeMillis());

            // 2. 生成签名
            String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
            requestParams.put("sign", signature);

            // 3. 发送请求
            String responseJson = executePost(url, requestParams);

            // 4. 解析响应并验证签名
            return parseAndVerifyResponse(responseJson, responseType);

        } catch (Exception e) {
            log.error("发送带签名和验签POST请求失败: {}", url, e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 发送普通POST请求（无签名）
     */
    public <T> T post(String url, Object request, Class<T> responseType) {
        try {
            String responseJson = executePost(url, request);
            return parseResponse(responseJson, responseType);
        } catch (Exception e) {
            log.error("发送POST请求失败: {}", url, e);
            throw new RuntimeException("调用外部接口失败: " + e.getMessage());
        }
    }

    /**
     * 执行POST请求
     */
    private String executePost(String url, Object body) throws IOException {
        String jsonBody = objectMapper.writeValueAsString(body);
        RequestBody requestBody = RequestBody.create( MediaType.parse("application/json; charset=utf-8"),jsonBody);

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("Content-Type", "application/json")
                .build();

        log.info("发送POST请求: {}, 数据: {}", url, jsonBody);

        try (Response response = okHttpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,response.code() + " " + response.message());
            }


            String responseBody = response.body().string();
            log.info("收到响应: {}", responseBody);

            checkBusinessResponseCode(responseBody);

            return responseBody;
        }
    }

    private void checkBusinessResponseCode(String responseJson) throws IOException {
        try {
            Map<String, Object> responseMap = objectMapper.readValue(responseJson,
                    new TypeReference<Map<String, Object>>() {
                    });

            Object codeObj = responseMap.get("code");
            if (codeObj != null) {
                int code = 0;
                if (codeObj instanceof Number) {
                    code = ((Number) codeObj).intValue();
                } else {
                    code = Integer.parseInt(codeObj.toString());
                }

                if (code != 200) {
                    String msg = (String) responseMap.get("msg");
                    // 700-799为平安银行错误
                    if (code >= 700 && code <= 799) {
                        throw new ServiceException(ErrorCodeEnum.WALLET_API_ERROR, msg);
                    } else if (code == 610 || msg.equals("支付密码不正确")) {
                        throw new ServiceException(ErrorCodeEnum.PASSWORD_ERROR);
                    } else {
                        throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                                "code: " + code + ", msg: " + msg);
                    }
                }
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            // 如果解析失败，说明可能不是标准格式，继续处理
            log.debug("无法解析响应码格式: {}", e.getMessage());
        }
    }

    /**
     * 解析响应
     */
    @SuppressWarnings("unchecked")
    private <T> T parseResponse(String responseJson, Class<T> responseType) throws Exception {
        // 解析为通用响应格式
        Map<String, Object> responseMap = objectMapper.readValue(responseJson,
                new TypeReference<Map<String, Object>>() {});


        // 如果返回类型是Map，直接返回
        if (responseType == Map.class) {
            return (T) responseMap;
        }

        // 提取data字段
        Object data = responseMap.get("data");
        if (data != null && responseType != Object.class) {
            if (data instanceof List) {
                // 保持List结构，让调用方处理具体类型转换
                return  (T)JSONObject.toJSONString(data);
            }
            return objectMapper.convertValue(data, responseType);
        }

        return objectMapper.convertValue(responseMap, responseType);
    }

    /**
     * 解析响应并验证签名
     */
    @SuppressWarnings("unchecked")
    private <T> T parseAndVerifyResponse(String responseJson, Class<T> responseType) throws Exception {
        // 解析为Map来验证签名
        Map<String, Object> responseMap = objectMapper.readValue(responseJson,
                new TypeReference<Map<String, Object>>() {});

        // 验证响应签名
        String responseSign = (String) responseMap.get("sign");
        if (responseSign != null) {
            // 移除sign字段后进行验签
            Map<String, Object> verifyParams = new HashMap<>(responseMap);

            boolean isValid = RsaSignUtil.verifySign(verifyParams, walletPublicKey);
            if (!isValid) {
                throw new SecurityException("响应签名验证失败");
            }
            log.debug("响应签名验证成功");
        }

        // 返回指定类型的数据
        return parseResponse(responseJson, responseType);
    }

    /**
     * 转换为Map
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> convertToMap(Object obj) {
        if (obj == null){
            return new HashMap<>();
        }
        if (obj instanceof Map) {
            return (Map<String, Object>) obj;
        }
        Map<String, Object> map = objectMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {
        });
        //门店映射
        if (map.containsKey(STORE_ID)){
            String key  = RedisConstant.STORE_ID_MAPPING;
            String storeId = (String) map.get(STORE_ID);
            String storeIdMapping = redisUtilPool.hashGet(key, storeId);
            if (StringUtil.isNotEmpty(storeIdMapping)){
                map.put(STORE_ID,storeIdMapping);
            }
        }
        return map;
    }

}
