package com.cool.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.dto.*;
import com.cool.store.dto.contract.ContractCallbackDTO;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.EnterpriseUserRoleDao;
import com.cool.store.dao.StoreDao;
import com.cool.store.dto.GetAccessTokenDTO;
import com.cool.store.dto.HqtTokenDTO;
import com.cool.store.dto.ModifyPasswordDTO;
import com.cool.store.dto.XgjOrganizationDTO;
import com.cool.store.entity.EnterpriseUserDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.UserRoleEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.ZxjpApiRequest;
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
import com.cool.store.request.xgj.ReceiptRequest;
import com.cool.store.response.XgjAccessTokenDTO;
import com.cool.store.response.XgjBaseResponse;
import com.cool.store.response.XgjOrganizationResponse;
import com.cool.store.response.huoma.ShopBaseInfoResponse;
import com.cool.store.response.oppty.OpportunityApiResponse;
import com.cool.store.service.PushService;
import com.cool.store.utils.HmacSigner;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.poi.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author suzhuhong
 * @Date 2025/4/9 14:24
 * @Version 1.0
 */
@Service
@Slf4j
public class PushServiceImpl implements PushService {

    @Value("${spring.profiles.active}")
    private String active;

    @Value("${api.auth.url}")
    private String url;

    @Value("${api.auth.username}")
    private String username;

    @Value("${api.auth.secret}")
    private String secret;

    @Value("${xgj.api.auth.url}")
    private String xgjUrl;

    @Value("${xgj.api.token.url}")
    private String xgjTokenUrl;

    @Value("${xgj.api.auth.username}")
    private String xgjUsername;

    @Value("${xgj.api.auth.secret}")
    private String xgjSecret;

    @Value("${yls.api.auth.url}")
    private String ylsUrl;

    @Value("${yls.api.auth.username}")
    private String ylsUsername;

    @Value("${yls.api.auth.secret}")
    private String ylsSecret;

    @Value("${xzg.api.auth.url}")
    private String xzgUrl;

    @Value("${ask.bot.url}")
    private String askBotUrl;

    @Value("${hqt.token.url}")
    private String hqtTokenUrl;

    @Value("${hqt.token.username}")
    private String hqtUsername;

    @Value("${hqt.token.grant_type}")
    private String hqtGrantType;

    @Value("${hqt.token.client.id}")
    private String hqtClientId;
    @Value("${hqt.token.client.secret}")
    private String hqtClientSecret;

    @Resource
    OkHttpClient okHttpClient;
    @Resource
    ObjectMapper objectMapper;

    @Resource
    private RedisUtilPool redisUtilPool;

    @Value("${mybatis.configuration.variables.enterpriseId}")
    private String eid;

    @PostConstruct
    public void init() {
        okHttpClient = okHttpClient.newBuilder()
                .connectTimeout(10, TimeUnit.SECONDS)    // 连接超时
                .readTimeout(30, TimeUnit.SECONDS)       // 读取超时
                .writeTimeout(30, TimeUnit.SECONDS)      // 写入超时
                .build();
    }

    @Override
    public Boolean pushDataToXGJ(ZxjpApiRequest zxjpApiRequest) {
        String apiUrl = xgjUrl + "/dmp/one-id/open/addStore";
        return executeApiCall(apiUrl, zxjpApiRequest, Boolean.class, xgjUsername, xgjSecret);
    }

    @Override
    public Boolean pushFranchiseFeeToXGJ(PushFranchiseFeeRequest request) {
        String apiUrl = xgjUrl + "/dmp/dmp-join/open/franchiseeBill";
        return executePostApiCall(apiUrl, request, Boolean.class, xgjUsername, xgjSecret,getXgjAccessToken().getAccess_token());
    }
    @Override
    public ContractCallbackDTO pushContract(ContractInformationDTO contractInformationDTO) {
        String apiUrl = xgjUrl + "/dmp/dmp-join/open/franchiseContract";
        return executePostApiCall(apiUrl, contractInformationDTO, ContractCallbackDTO.class, xgjUsername, xgjSecret,getXgjAccessToken().getAccess_token());
    }

    @Override
    public Boolean pushReceiptToXGJ(ReceiptRequest request) {
        String apiUrl = xgjUrl + "/dmp/dmp-join/open/franchiseeReceipts";
        return executePostApiCall(apiUrl, request, Boolean.class, xgjUsername, xgjSecret,getXgjAccessToken().getAccess_token());
    }

    @Override
    public Boolean pushDataToPOS(ZxjpApiRequest zxjpApiRequest) {
        String apiUrl = url + "/dzgV1/zxcrm/shop/upsert";
        return executeApiCall(apiUrl, zxjpApiRequest, Boolean.class, username, secret);
    }

    private Boolean modifyXGJPassword(ModifyPasswordDTO dto) {
        String apiUrl = xgjUrl + "/dmp/one-id/open/updateStorePassword";
        return executeApiCall(apiUrl, dto, Boolean.class, xgjUsername, xgjSecret);
    }

    private Boolean modifyPosPassword(ModifyPasswordDTO dto) {
        String apiUrl = url + "/dzgV1/zxcrm/business_user/modifyPassword";
        return executeApiCall(apiUrl, dto, Boolean.class, username, secret);
    }



    @Override
    public Boolean modifyDownstreamSystem(ModifyPasswordDTO modifyPasswordDTO) {
        this.modifyPosPassword(modifyPasswordDTO);
        this.modifyXGJPassword(modifyPasswordDTO);
        return Boolean.TRUE;
    }

    @Override
    public String getYlsToken(GetAccessTokenDTO dto) {
        String yls = redisUtilPool.getString("yls");
        if (StringUtils.isNotBlank(yls)) {
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,"云流水系统修复中");
        }
        String apiUrl = ylsUrl + "/Store.axd?action=getToken";
        return executeApiCall(apiUrl, dto, String.class, ylsUsername, ylsSecret);
    }

    @Override
    public String getXzgToken(GetAccessTokenDTO dto) {
        String apiUrl = xzgUrl + "/api/supply-chain/get-token-byshopcode";
        //不需要验签
        return executeApiCall(apiUrl, dto, String.class, "", "");
    }

    @Resource
    EnterpriseUserDAO enterpriseUserDAO;
    @Resource
    EnterpriseUserRoleDao enterpriseUserRoleDao;
    @Resource
    StoreDao storeDao;

    @Override
    public String getPosToken(GetAccessTokenDTO dto) {
        EnterpriseUserDO enterpriseUserDO = enterpriseUserDAO.selectByMobile(dto.getMobile());
        if (enterpriseUserDO != null){
            List<Long> userRoleIds = enterpriseUserRoleDao.getUserRoleIds(enterpriseUserDO.getUserId());
            //如果userRoleIds包含督导。大区总。分部负责人任何一个 使用当前门店的手机号
            if (userRoleIds.contains(UserRoleEnum.SUPERVISION.getCode()) ||
                    userRoleIds.contains(UserRoleEnum.HEAD_OF_DIVISION.getCode()) ||
                    userRoleIds.contains(UserRoleEnum.SERVICE_PACKAGE_DEDICATED.getCode()) ||
                    userRoleIds.contains(UserRoleEnum.REGION_MANAGER.getCode())) {
                StoreDO store = storeDao.getByStoreNum(dto.getShopCode());
                if (store != null&&StringUtils.isNotEmpty(store.getTelephone())){
                    dto.setMobile(store.getTelephone());
                }else {
                    throw new ServiceException(ErrorCodeEnum.STORE_MOBILE_NOT_EXIST);
                }
            }
        }
        String apiUrl = url + "/dzgV1/zxcrm/business_user/generateToken";
        return executeApiCall(apiUrl, dto, String.class, username, secret);
    }


    @Override
    public List<XgjOrganizationDTO> getXgjOrganization(String parentId) {
        String key = active+"_XgjOrganization_" + eid;
        String resObject = redisUtilPool.getString(key);
        if (StringUtils.isBlank(resObject)) {
            String apiUrl = xgjUrl + "/dmp/one-id/open/organization";
            resObject = JSONObject.toJSONString(executeApiGetCall(apiUrl, null, Object.class, xgjUsername, xgjSecret));
           redisUtilPool.setNxExpire(key, resObject, 7200000);
        }
        List<XgjOrganizationDTO> response = new ArrayList<>();
        if (StringUtils.isNotBlank(resObject)) {
            // 使用 Jackson 将 Object 转换为目标类型
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                response = objectMapper.readValue(resObject, new TypeReference<List<XgjOrganizationDTO>>() {
                });
            } catch (JsonProcessingException e) {
                throw new ServiceException("数据类型转化异常： " + e.getMessage());
            }

        }
        List<XgjOrganizationDTO> filteredList = response.stream()
                .filter(customer -> customer.getParentId().equals(parentId))
                .collect(Collectors.toList());
        return filteredList;

    }

    @Override
    public XgjAccessTokenDTO getXgjAccessToken() {
        String apiUrl = xgjTokenUrl + "/oauth2/token?grant_type=client_credentials&scope=server";
        String clientId = "dmp-join";
        String clientSecret = "dmp20250528";
        String auth = clientId + ":" + clientSecret;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        byte[] bytes = new byte[0];
        Request request = new Request.Builder()
                .url(apiUrl)
                .post(RequestBody.create(MediaType.parse("application/json; charset=UTF-8"),bytes))
                .header("Authorization", "Basic " + encodedAuth)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                        "HTTP请求失败，状态码: " + response.code());
            }
            String responseBody = response.body().string();
            XgjAccessTokenDTO xgjAccessTokenDTO = objectMapper.readValue(responseBody, XgjAccessTokenDTO.class);
            return xgjAccessTokenDTO;
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
        }
    }

    @Override
    public Integer getUnReadMessageNum(String partnerId) {
        String apiUrl =askBotUrl  +  "/api-pluto/session/getUnReadMessageNum?userId="+partnerId;
        log.info("获取小正AI消息数据开始 url：{}", apiUrl);
        Request request = new Request.Builder()
                .url(apiUrl)
                .get()
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                        "HTTP请求失败，状态码: " + response.code());
            }
            String responseBody = response.body().string();
            log.info("getUnReadMessageNum response num：{}", responseBody);
            return Integer.valueOf(responseBody);
        } catch (Exception e) {
            log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
        }
    }

    @Override
    public HqtTokenDTO getHqtToken() {
        String url = hqtTokenUrl + "/hecom-tenancy/oauth/token";
        String auth = hqtClientId + ":" + hqtClientSecret;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        RequestBody formBody = new FormBody.Builder()
                .add("grant_type", hqtGrantType)
                .add("username", hqtUsername)
                .build();
        Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .addHeader("Authorization", "Basic " + encodedAuth)
                .addHeader("Host", "tc.cloud.hecom.cn")
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.info("HTTP请求失败，msg: " + response.message());
                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                        "HTTP请求失败，状态码: " + response.code());
            }
            String responseBody = response.body().string();
            HqtTokenDTO hqtTokenDTO = objectMapper.readValue(responseBody, HqtTokenDTO.class);
            return hqtTokenDTO;
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
        }
    }


    private <T> T executeApiCall(String url, Object requestBody, Class<T> responseType, String username, String secret){
        return executePostApiCall(url,requestBody,responseType,username,secret,null);
    }


    private <T> T executePostApiCall(String url, Object requestBody, Class<T> responseType, String username, String secret,String accessToken) {
        // 1. 打印请求前日志
        logRequest(url, requestBody);

        try {
            Request request = buildRequest(requestBody, url, username, secret,accessToken);

            request.headers().names().forEach(x->{
                log.info(x+": {}",request.header(x));
            });

            try (Response response = okHttpClient.newCall(request).execute()) {
                // 2. 获取原始响应内容
                String responseBody = response.body().string();

                // 3. 打印响应日志
                logResponse(url, response.code(), responseBody);

                if (!response.isSuccessful()) {
                    throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                            "HTTP请求失败，状态码: " + response.code());
                }

                // 4. 解析响应
                JavaType javaType = objectMapper.getTypeFactory()
                        .constructParametricType(OpportunityApiResponse.class, responseType);

                OpportunityApiResponse<T> apiResponse = objectMapper.readValue(responseBody, javaType);

                if (apiResponse.getCode() != 200) {
                    throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,apiResponse.getMsg());
                }
                return apiResponse.getData();
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
        }
    }

    private void logRequest(String url, Object requestBody) {
        if (log.isInfoEnabled()) {
            try {
                log.info("\n======= 请求开始 =======\n" +
                                "API地址: {}\n" +
                                "请求参数: {}\n" +
                                "======= 请求结束 =======",
                        url,
                        objectMapper.writerWithDefaultPrettyPrinter()
                                .writeValueAsString(requestBody));
            } catch (JsonProcessingException e) {
                log.warn("日志JSON序列化失败", e);
            }
        }
    }

    /**
     * 记录响应日志
     */
    private void logResponse(String url, int statusCode, String responseBody) {
        if (log.isInfoEnabled()) {
            try {
                // 尝试美化JSON输出
                Object json = objectMapper.readValue(responseBody, Object.class);
                String prettyResponse = objectMapper.writerWithDefaultPrettyPrinter()
                        .writeValueAsString(json);

                log.info("\n======= 响应开始 =======\n" +
                                "API地址: {}\n" +
                                "HTTP状态码: {}\n" +
                                "响应内容: {}\n" +
                                "======= 响应结束 =======",
                        url,
                        statusCode,
                        prettyResponse);
            } catch (Exception e) {
                // 非JSON响应或解析失败时直接输出原始内容
                log.info("\n======= 响应开始 =======\n" +
                                "API地址: {}\n" +
                                "HTTP状态码: {}\n" +
                                "原始响应: {}\n" +
                                "======= 响应结束 =======",
                        url,
                        statusCode,
                        responseBody);
            }
        }
    }


    private Request buildRequest(Object requestBody, String url, String username, String secret,String accessToken) {

        try {
            Map<String, String> authHeaders = HmacSigner.generateHeaders(
                    username, secret, JSONObject.toJSONString(requestBody));

            log.debug("签名生成 -  签名结果: {}", JSONObject.toJSONString(authHeaders));

            RequestBody body = RequestBody.create(MediaType.parse("application/json"),
                    JSONObject.toJSONString(requestBody)
            );
            Request.Builder builder = new Request.Builder()
                    .url(url)
                    .post(body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .addHeader("x-Date", authHeaders.get("x-Date"))
                    .addHeader("Digest", authHeaders.get("Digest"));
            if (!url.contains("get-token-byshopcode")&&StringUtils.isEmpty(accessToken)){
                builder.addHeader("Authorization", authHeaders.get("Authorization"));
            }
            //新管家特定接口
            if (StringUtils.isNotEmpty(accessToken)){
                builder.addHeader("Authorization", "Bearer "+accessToken);
            }
            return builder.build();
        } catch (Exception e) {
            throw new ServiceException(ErrorCodeEnum.THIRD_API_SIGN_ERROR);
        }
    }

    private <T> T executeApiGetCall(String url, Map<String, Object> requestParams, Class<T> responseType, String username, String secret) {
        //1.处理请求参数
        String buildUrlWithParams = buildUrlWithParams(url, requestParams);
        // 2. 打印请求前日志
        logRequest(buildUrlWithParams, requestParams);

        try {
            Request request = buildGetRequest(url, username, secret);

            try (Response response = okHttpClient.newCall(request).execute()) {
                // 2. 获取原始响应内容
                String responseBody = null;
                if (response.body() != null) {
                    responseBody = response.body().string();
                }

                // 3. 打印响应日志
                logResponse(url, response.code(), responseBody);

                if (!response.isSuccessful()) {
                    throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
                            "HTTP请求失败，状态码: " + response.code());
                }

                // 4. 解析响应
                JavaType javaType = objectMapper.getTypeFactory()
                        .constructParametricType(XgjBaseResponse.class, responseType);

                XgjBaseResponse<T> apiResponse = objectMapper.readValue(responseBody, javaType);

                if (apiResponse.getRetCode() != 200) {
                    throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,apiResponse.getRetMsg());
                }

                return apiResponse.getRetData();
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
        }
    }

    private Request buildGetRequest(String url, String username, String secret) {

        try {
            return new Request.Builder()
                    .url(url)
                    .get()
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .addHeader("X-Key", username)
                    .addHeader("X-Secret", secret)
                    .build();
        } catch (Exception e) {
            throw new ServiceException(ErrorCodeEnum.THIRD_API_SIGN_ERROR);
        }
    }

    public String buildUrlWithParams(String baseUrl, Map<String, Object> requestParams) {
        if (requestParams == null || requestParams.isEmpty()) {
            // 如果没有参数，直接返回基础 URL
            return baseUrl;
        }

        StringBuilder urlBuilder = new StringBuilder(baseUrl);

        // 检查是否需要添加 "?" 或 "&"
        if (!baseUrl.contains("?")) {
            urlBuilder.append("?");
        } else if (!baseUrl.endsWith("&")) {
            urlBuilder.append("&");
        }

        try {
            // 遍历参数并拼接
            for (Map.Entry<String, Object> entry : requestParams.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();

                if (value != null) {
                    // 对键和值进行 URL 编码
                    urlBuilder.append(URLEncoder.encode(key, "UTF-8"))
                            .append("=")
                            .append(URLEncoder.encode(value.toString(), "UTF-8"))
                            .append("&");
                }
            }

            // 删除最后一个多余的 "&"
            if (urlBuilder.charAt(urlBuilder.length() - 1) == '&') {
                urlBuilder.deleteCharAt(urlBuilder.length() - 1);
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Error encoding URL parameters", e);
        }

        return urlBuilder.toString();
    }


}
