package com.trade.service.thirdparty.xiaotu.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.trade.common.constant.CacheConstants;
import com.trade.common.exception.ServiceException;
import com.trade.common.redis.RedisCache;
import com.trade.common.utils.http.HttpClientUtils;
import com.trade.common.utils.http.HttpConfig;
import com.trade.common.utils.http.HttpHeader;
import com.trade.service.DictConstants;
import com.trade.service.thirdparty.xiaotu.configuration.XiaotuConfiguration;
import com.trade.service.thirdparty.xiaotu.dto.*;
import com.trade.service.thirdparty.xiaotu.dto.filingdoc.FilingDocWriteRequest;
import com.trade.service.thirdparty.xiaotu.service.XiaotuRequestService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class XiaotuRequestServiceImpl implements XiaotuRequestService {

    private static final Logger logger = LoggerFactory.getLogger(XiaotuRequestServiceImpl.class);
    private static final String CONTENT_TYPE_JSON = "application/json";
    @Resource
    private RedisCache redisCache;
    @Resource
    private XiaotuConfiguration xiaotuConfiguration;

    private HttpHeader getCommonHeader() {
        return HttpHeader.custom().other("accessClientId", xiaotuConfiguration.getAccessClientId())
                .other("ftype", xiaotuConfiguration.getFtype())
                .other("gatewaAppKey", xiaotuConfiguration.getGatewayAppKey());
    }

    private HttpHeader getBusinessCommonHeader(String xtUid, String xtEid) {
        return HttpHeader.custom().other("accessClientId", xiaotuConfiguration.getAccessClientId())
                .other("ftype", xiaotuConfiguration.getFtype())
                .other("gatewaAppKey", xiaotuConfiguration.getGatewayAppKey())
                .other("accessToken", getAccessToken(xtUid, xtEid));
    }

    /**
     * 获取小图accessToken 和小图约定token的有效期为60分钟
     * 
     * @param xtUid 小图用户id
     * @param xtEid 小图企业id
     * @return 小图accessToken
     */
    private String getAccessToken(String xtUid, String xtEid) {
        String cacheKey = CacheConstants.XIAOTU_ACCESS_TOKEN + "_" + xtUid + "_" + xtEid;
        String accessToken = redisCache.getCacheObject(cacheKey);
        if (StrUtil.isEmpty(accessToken)) {
            String resp = HttpClientUtils
                    .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                            .json(JSON.toJSONString(new RequestToken(xtEid, xtUid)))
                            .url(xiaotuConfiguration.getGetAccessTokenUrl()));
            CommonResponse<GetTokenResponse> commonResponse = JSON.parseObject(resp,
                    new TypeReference<CommonResponse<GetTokenResponse>>() {
                    });
            if (commonResponse == null || !commonResponse.isSuccess() || commonResponse.getBody() == null) {
                logger.error("获取【退税系统】accessToken失败,resp={}", resp);
                throw new RuntimeException("获取【退税系统】accessToken失败");
            }
            accessToken = commonResponse.getBody().getAccessToken();
            if (StringUtils.isEmpty(accessToken)) {
                logger.error("获取【退税系统】accessToken为空,resp={}", resp);
                throw new RuntimeException("获取【退税系统】accessToken为空");
            }
            redisCache.setCacheObject(cacheKey, accessToken, 30, TimeUnit.MINUTES);
            return accessToken;
        }
        return accessToken;
    }

    @Override
    public RegisterUserResponse registerUser(RegisterUserRequest request) {
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getRegisterUserUrl()));
        logger.info("【退税系统】:用户信息注册,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getRegisterUserUrl());
        CommonResponse<RegisterUserResponse> commonResponse = JSON.parseObject(resp,
                new TypeReference<CommonResponse<RegisterUserResponse>>() {
                });
        if (commonResponse == null || !commonResponse.isSuccess() || commonResponse.getBody() == null) {
            throw new RuntimeException(
                    "【退税系统】:用户信息注册失败：" + (commonResponse == null || StrUtil.isEmpty(commonResponse.getMsg()) ? ""
                            : commonResponse.getMsg()));
        }
        return commonResponse.getBody();
    }

    @Override
    public Boolean updateUser(UpdateUserRequest request) {
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getUpdateUserUrl()));
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        return commonResponse.isSuccess();
    }

    private UserInfoDto getUserInfo(SearchUserRequest request) {
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getSearchUserUrl()));
        logger.info("【退税系统】:用户信息查询,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getSearchUserUrl());
        CommonResponse<SearchUserResponse> commonResponse = JSON.parseObject(resp,
                new TypeReference<CommonResponse<SearchUserResponse>>() {
                });
        if (commonResponse == null || !commonResponse.isSuccess() || commonResponse.getBody() == null) {
            logger.error("【退税系统】:用户信息查询失败,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:用户信息查询失败");
        }
        return commonResponse.getBody().getYhList().stream().filter(o -> DictConstants.SYS_YES.equals(o.getYxbz()))
                .findFirst().orElse(null);
    }

    @Override
    public UserInfoDto searchUserByUserId(String userId) {
        SearchUserRequest request = new SearchUserRequest();
        request.setYhuuid1(userId);
        return getUserInfo(request);
    }

    @Override
    public UserInfoDto searchUserByUserName(String userName) {
        SearchUserRequest request = new SearchUserRequest();
        request.setYddh(userName);
        return getUserInfo(request);
    }

    @Override
    public RegisterEnterpriseResponse registerEnterprise(RegisterEnterpriseRequest request) {
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getRegisterEnterpriseUrl()));
        logger.info("【退税系统】:企业信息注册,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getRegisterEnterpriseUrl());
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse == null || !commonResponse.isSuccess() || commonResponse.getBody() == null) {
            throw new RuntimeException(
                    "【退税系统】:企业信息注册失败：" + (commonResponse == null || StrUtil.isEmpty(commonResponse.getMsg()) ? ""
                            : commonResponse.getMsg()));
        }
        return JSON.parseObject(JSON.parseObject(resp).getString("body"), RegisterEnterpriseResponse.class);
    }

    @Override
    public Boolean updateEnterprise(UpdateEnterpriseRequest request) {
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getUpdateEnterpriseUrl()));
        logger.info("【退税系统】:企业信息更新,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getUpdateEnterpriseUrl());
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            logger.error("【退税系统】:企业信息更新失败,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:企业信息更新失败");
        }
        return commonResponse.isSuccess();
    }

    @Override
    public EnterpriseInfo searchEnterprise(String xtUid, String certNo, String taxNo) {
        SearchEnterpriseRequest request = new SearchEnterpriseRequest();
        request.setYhuuid1(xtUid);
        request.setShxydm(certNo);
        request.setNsrsbh(taxNo);
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getSearchEnterpriseUrl()));
        logger.info("【退税系统】:企业信息查询,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getSearchEnterpriseUrl());
        CommonResponse<SearchEnterpriseResponse> commonResponse = JSON.parseObject(resp,
                new TypeReference<CommonResponse<SearchEnterpriseResponse>>() {
                });
        if (commonResponse == null || !commonResponse.isSuccess() || commonResponse.getBody() == null) {
            logger.error("【退税系统】:企业信息查询失败,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:企业信息查询失败");
        }
        return commonResponse.getBody().getQyList().stream().findFirst().orElse(null);
    }

    @Override
    public Boolean bindUserAndEnterprise(String xtUid, String xtEid) {
        BindEnterpriseUserRequest request = new BindEnterpriseUserRequest();
        request.setYhuuid1(xtUid);
        request.setSbqyuuid(xtEid);
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getBindEnterpriseUserUrl()));
        logger.info("【退税系统】:新增用户企业关系,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getBindEnterpriseUserUrl());
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            logger.error("【退税系统】:新增用户企业关系失败,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:新增用户企业关系失败");
        }
        return commonResponse.isSuccess();
    }

    @Override
    public Boolean unbindUserAndEnterprise(String xtUid, String xtEid) {
        UnbindEnterpriseUserRequest request = new UnbindEnterpriseUserRequest();
        request.setYhuuid1(xtUid);
        request.setSbqyuuid(xtEid);
        String resp = HttpClientUtils
                .post(HttpConfig.custom().headers(getCommonHeader().contentType(CONTENT_TYPE_JSON).build())
                        .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getUnbindEnterpriseUserUrl()));
        logger.info("【退税系统】:用户企业关系解除,req={},resp={},header={}，url={}", JSON.toJSONString(request), resp,
                JSON.toJSONString(getCommonHeader().build()), xiaotuConfiguration.getUnbindEnterpriseUserUrl());
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            logger.error("【退税系统】:用户企业关系解除失败,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:用户企业关系解除失败");
        }
        return commonResponse.isSuccess();
    }

    @Override
    public List<CommodityResponse> taxRefundRateInquiry(CommodityRequest commodityRequest,
            BusinessCommonRequest businessCommonRequest) {
        String request = JSON.toJSONString(commodityRequest);
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(JSON.toJSONString(commodityRequest)).url(xiaotuConfiguration.getTsslcxUrl()));
        CommonResponse commonResponseCheck = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponseCheck.getBody() == null || commonResponseCheck.getBody().toString().equals("[]")) {
            throw new ServiceException("未检索到商品信息");
        }
        if (commonResponseCheck != null && !commonResponseCheck.isSuccess()) {
            logger.error("【退税系统】:退税税率查询接口,req={},resp={}", request, resp);
            throw new RuntimeException("【退税系统】:退税税率查询接口失败");
        }
        List<CommodityResponse> commonResponse = JSON.parseObject(commonResponseCheck.getBody().toString(),
                new TypeReference<List<CommodityResponse>>() {
                });
        logger.info("【退税系统】:退税税率查询接口,req={},resp={}", request, resp);
        return commonResponse;
    }

    @Override
    public List<CommodityCustomsTariffRespose> commodityCustomsTariffInquiry(String spid,
            BusinessCommonRequest businessCommonRequest) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("spid", spid);
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(jsonObject.toJSONString()).url(xiaotuConfiguration.getHgszcxUrl()));
        CommonResponse commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse.getBody() == null || commonResponse.getBody().toString().equals("[]")) {
            // throw new ServiceException("未检索到商品信息");
            logger.error("【退税系统】:海关税则查询接口未检索到商品信息,req={},resp={}", spid, resp);
            return new ArrayList<CommodityCustomsTariffRespose>();
        }
        String rows = JSON.parseObject(commonResponse.getBody().toString()).getString("rows");
        List<CommodityCustomsTariffRespose> commodityCustoms = JSON.parseObject(rows,
                new TypeReference<List<CommodityCustomsTariffRespose>>() {
                });
        if (commonResponse != null && !commonResponse.isSuccess()) {
            logger.error("【退税系统】:海关税则查询接口,req={},resp={}", spid, resp);
            throw new RuntimeException("【退税系统】:海关税则查询接口失败");
        }
        logger.info("【退税系统】:退税税率查询接口,req={},resp={}", spid, resp);
        return commodityCustoms;
    }

    /**
     * 【退税系统】通用查询接口 - 带分页
     *
     * @param request 请求参数
     * @param <T> 返回类型
     * @return List<T>
     */
    public <T extends CommonResultRows> CommonQueryResponse<T> queryCommonResponse(CommonQueryRequest request,
            BusinessCommonRequest businessCommonRequest, Class<T> clazz) {
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(JSON.toJSONString(request)).url(request.getUrl()));
        CommonResponse<String> commonResponse = JSON.parseObject(resp, new TypeReference<CommonResponse<String>>() {
        });
        logger.info("查询【退税系统】数据,req={},resp={}", request, resp);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            throw new RuntimeException("查询【退税系统】数据失败");
        }
        return JSON.parseObject(commonResponse.getBody(), new TypeReference<CommonQueryResponse<T>>(clazz) {
        });
    }

    @Override
    public List<CustomsDeclarationResponse> customsDeclarationInquiry(CustomsDeclarationRequest request,
            BusinessCommonRequest businessCommonRequest) {
        request.setUrl(xiaotuConfiguration.getCustomsDeclarationUrl());
        CommonQueryResponse<CustomsDeclarationResponse> response = queryCommonResponse(request, businessCommonRequest,
                CustomsDeclarationResponse.class);
        if (response == null || response.getRows() == null || response.getRows().isEmpty()) {
            return Collections.emptyList();
        }
        return response.getRows();
    }

    @Override
    public List<InvoiceQueryResponse> invoiceQuery(InvoiceQueryRequset request,
            BusinessCommonRequest businessCommonRequest) {
        request.setUrl(xiaotuConfiguration.getInvoiceQueryUrl());
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(JSON.toJSONString(request)).url(request.getUrl()));
        CommonResponse<?> commonResponse = JSON.parseObject(resp, CommonResponse.class);
        logger.info("查询【退税系统】数据,req={},resp={}", request, resp);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            throw new RuntimeException("查询【退税系统】数据失败");
        }
        if (commonResponse.getBody() == null) {
            return new ArrayList<InvoiceQueryResponse>();
            // throw new ServiceException("未检索到数据");
        }
        CommonQueryResponse<InvoiceQueryResponse> commonQueryResponse = JSON.parseObject(
                commonResponse.getBody().toString(), new TypeReference<CommonQueryResponse<InvoiceQueryResponse>>() {
                });
        return commonQueryResponse.getRows();
    }

    @Override
    public InvoiceFileResponse invoiceFileQuery(String jhpzh, BusinessCommonRequest businessCommonRequest) {
        JSONObject jhpzhJson = new JSONObject();
        jhpzhJson.put("jhpzh", jhpzh);
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(jhpzhJson.toJSONString()).url(xiaotuConfiguration.getInvoiceDownUrl()));
        CommonResponse<InvoiceFileResponse> commonResponse = JSON.parseObject(resp,
                new TypeReference<CommonResponse<InvoiceFileResponse>>() {
                });
        if (commonResponse != null && !commonResponse.isSuccess()) {
            logger.error("【退税系统】发票文件查询接口,jhpzh={},resp={}", jhpzh, resp);
            throw new RuntimeException("【退税系统】发票文件接口失败");
        }
        logger.info("【退税系统】发票文件查询接口,jhpzh={},resp={}", jhpzh, resp);
        return commonResponse.getBody();
    }

    @Override
    public String getExportRebateUrl(String xtUid, String xtEid, String jumpUrl) {
        String accessToken = getAccessToken(xtUid, xtEid);
        return xiaotuConfiguration.getSystemIntegrationUrl() + "?accessToken=" + accessToken + "&jumpUrl=" + jumpUrl;
    }

    @Override
    public CommonQueryResponse<TradeExportAndPurchaseDetailsResponse> queryTradeExportAndPurchaseDetails(
            ExportDetailsRequest request, BusinessCommonRequest businessCommonRequest) {
        request.setUrl(xiaotuConfiguration.getGetTradeExportAndPurchaseDetailsUrl());
        CommonQueryResponse<TradeExportAndPurchaseDetailsResponse> response = queryCommonResponse(request,
                businessCommonRequest, TradeExportAndPurchaseDetailsResponse.class);
        if (response == null || CollUtil.isEmpty(response.getRows())) {
            return null;
        }
        return response;
    }

    @Override
    public CommonQueryResponse<ProduceExportDetailsResponse> queryProduceExportDetails(ExportDetailsRequest request,
            BusinessCommonRequest businessCommonRequest) {
        request.setUrl(xiaotuConfiguration.getGetProduceExportDetailsUrl());
        CommonQueryResponse<ProduceExportDetailsResponse> response = queryCommonResponse(request, businessCommonRequest,
                ProduceExportDetailsResponse.class);
        if (response == null || CollUtil.isEmpty(response.getRows())) {
            return null;
        }
        return response;
    }

    @Override
    public boolean filingDocumentWrite(FilingDocWriteRequest request, BusinessCommonRequest businessCommonRequest) {
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(JSON.toJSONString(request)).url(xiaotuConfiguration.getFilingDocumentWriteUrl()));
        CommonResponse<?> commonResponse = JSON.parseObject(resp, CommonResponse.class);
        if (commonResponse == null || !commonResponse.isSuccess()) {
            logger.error("调用【退税系统】备案单证写入接口失败,req={},resp={}", request, resp);
            throw new RuntimeException("调用【退税系统】备案单证写入接口失败");
        }
        return commonResponse.isSuccess();
    }

    @Override
    public customsDeclarationFileResponse customsDeclarationFileQuery(String bgdhgbh, String type,
            BusinessCommonRequest businessCommonRequest) {
        Map<String, String> params = new HashMap<>();
        params.put("bgdhgbh", bgdhgbh);
        params.put("type", type);
        String resp = HttpClientUtils.post(HttpConfig.custom()
                .headers(getBusinessCommonHeader(businessCommonRequest.getXtUid(), businessCommonRequest.getXtEid())
                        .contentType(CONTENT_TYPE_JSON).build())
                .json(JSON.toJSONString(params)).url(xiaotuConfiguration.getCustomsDeclarationDownUrl()));
        CommonResponse<customsDeclarationFileResponse> commonResponse = JSON.parseObject(resp,
                new TypeReference<CommonResponse<customsDeclarationFileResponse>>() {
                });
        if (null == commonResponse || !commonResponse.isSuccess()) {
            logger.error("调用报关单/协议文件下载接口失败,bgdhgbh={},resp={}", bgdhgbh, resp);
            throw new RuntimeException("【退税系统】报关单/协议文件下载失败");
        }
        logger.info("报关单/协议文件下载,jhpzh={},resp={}", bgdhgbh, resp);
        return commonResponse.getBody();
    }
}
