package com.yc.ship.module.trade.service.thirdsystem.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yc.ship.framework.common.util.json.JsonUtils;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.system.api.dict.DictDataApi;
import com.yc.ship.module.system.api.dict.dto.DictDataRespDTO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeVisitorDO;
import com.yc.ship.module.trade.dal.dataobject.refund.RefundDO;
import com.yc.ship.module.trade.enums.SellMethodEnum;
import com.yc.ship.module.trade.framework.common.MD5Utils;
import com.yc.ship.module.trade.framework.common.Md5;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.bo.TradeVisitorBO;
import com.yc.ship.module.trade.service.refund.TradeRefundRepositoryService;
import com.yc.ship.module.trade.service.thirdsystem.ThirdGateSystemService;
import com.yc.ship.module.trade.service.thirdsystem.bo.ThidrGateSystemVisitorBO;
import com.yc.ship.module.trade.service.thirdsystem.bo.ThirdGateSystemPushDataReqDTO;
import com.yc.ship.module.trade.service.thirdsystem.bo.ThirdGateSystemPushDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import java.util.*;


/**
 * 第三方门禁系统service实现
 */
@Service
@Slf4j
public class ThirdGateSystemServiceImpl implements ThirdGateSystemService {

    @Resource
    private ConfigApi configApi;
    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;
    @Resource
    private TradeRefundRepositoryService tradeRefundRepositoryService;

    @Override
    public void pushVisitor(Long orderId){
        this.batchPushVisitor(orderId,DateUtil.parseDate(DateUtil.today()));
    }

    @Override
    public void batchPushVisitor(Long orderId, Date useDate){
        int pageSize = 10000;
        int pageNo = 1;
        IPage<TradeVisitorBO> page = new Page<>(pageNo, pageSize);
        Long tenantId =Long.parseLong(configApi.getConfigValueByKey("system.tenantId"));
        TenantContextHolder.setIgnore(true);
        try {
            while (pageNo>=1){
                page.setCurrent(pageNo);
                IPage<TradeVisitorBO> pageData = tradeOrderRepositoryService.getVisitorListByDate(page,orderId,useDate,tenantId);
                if(CollUtil.isEmpty(pageData.getRecords())){
                    return;
                }
                for (TradeVisitorBO tradeVisitorDO : pageData.getRecords()) {
                    if(StringUtils.isNotBlank(tradeVisitorDO.getCredentialNo())) {
                        ThidrGateSystemVisitorBO visitorBO = new ThidrGateSystemVisitorBO();
                        visitorBO.setVisitorId(tradeVisitorDO.getId().toString());
                        visitorBO.setName(tradeVisitorDO.getName());
                        visitorBO.setCredentialNo(tradeVisitorDO.getCredentialNo());
                        visitorBO.setCredentialType(tradeVisitorDO.getCredentialType());
                        visitorBO.setProductName(tradeVisitorDO.getProductName());
                        visitorBO.setUseDate(tradeVisitorDO.getUseDate());
                        visitorBO.setSex(tradeVisitorDO.getGender());
                        visitorBO.setUseDate(tradeVisitorDO.getUseDate());
                        visitorBO.setSpecType(tradeVisitorDO.getSpecType());
                        visitorBO.setPlanName(tradeVisitorDO.getPlanName());
                        SpringUtil.getBean(ThirdGateSystemService.class).insertCertAsync(visitorBO);
                    }
                }
                pageNo++;
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("批量推送数据异常",e);
        }finally {
            TenantContextHolder.setIgnore(false);
        }
    }

    @Async
    @Override
    public void insertCertAsync(ThidrGateSystemVisitorBO visitorBO){
        SpringUtil.getBean(ThirdGateSystemService.class).insertCert(visitorBO);
    }

    @Override
    @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 3000, multiplier = 1.5))
    public void insertCert(ThidrGateSystemVisitorBO visitorBO){
        try{
            ThirdGateSystemPushDataReqDTO pushDataDTO = new ThirdGateSystemPushDataReqDTO();
            pushDataDTO.setTcid(visitorBO.getVisitorId());
            pushDataDTO.setTripdate(DateUtil.formatDate(visitorBO.getUseDate()));
            String[] names = visitorBO.getProductName().split("-");
            pushDataDTO.setProduct(names[0]);
            if (names.length > 1) {
                pushDataDTO.setTripmode(names[1]+visitorBO.getPlanName());
            } else {
                pushDataDTO.setTripmode(visitorBO.getProductName()+visitorBO.getPlanName());
            }
            //1 豪华游轮 0两坝一峡 2兼容
            pushDataDTO.setDeparture("宜昌港");
            if(visitorBO.getProductName().indexOf("升船机")!=-1){
                pushDataDTO.setDeparture("升船机");
            }
            if (visitorBO.getSpecType().equals("half")) {
                pushDataDTO.setTickettype("儿童票");
            } else if (visitorBO.getSpecType().equals("free")) {
                pushDataDTO.setTickettype("免票");
            } else if (visitorBO.getSpecType().equals("car_seat")) {
                pushDataDTO.setTickettype("车位");
            } else if (visitorBO.getSpecType().equals("car_yd")) {
                pushDataDTO.setTickettype("优待票");
            } else if (visitorBO.getSpecType().equals("carrying_children")) {
                pushDataDTO.setTickettype("携童票");
            } else if (visitorBO.getSpecType().equals("other")) {
                pushDataDTO.setTickettype("其他");
            } else {
                pushDataDTO.setTickettype("全票");
            }
            DictDataRespDTO credentialTypeDictData = dictDataApi.getDictData("credential_type", String.valueOf(visitorBO.getCredentialType()));
            pushDataDTO.setCerttype(credentialTypeDictData == null ? "身份证" : credentialTypeDictData.getLabel());
            pushDataDTO.setName(visitorBO.getName());
            Integer gender = visitorBO.getSex();
            try {
                if(gender==null && visitorBO.getCredentialNo().length()==18){
                    gender = IdcardUtil.getGenderByIdCard(visitorBO.getCredentialNo());
                }
            } catch (Exception e) {
                log.error("获取性别异常",e);
                gender = 0;
            }
            if(gender==null){
                gender = 0;
            }
            DictDataRespDTO sexDictData = dictDataApi.getDictData("system_user_sex", String.valueOf(gender));
            pushDataDTO.setSex(sexDictData.getLabel()!=null?sexDictData.getLabel():"男");
            pushDataDTO.setCert(visitorBO.getCredentialNo());
            // 第一次推送
            sendPushRequest(pushDataDTO, visitorBO.getVisitorId());
            // 检查是否需要额外推送
            if (names.length > 1 && "常规全域游船去车回".equals(names[1])) {
                // 创建第二个推送请求
                ThirdGateSystemPushDataReqDTO secondPushDTO = new ThirdGateSystemPushDataReqDTO();
                BeanUtils.copyProperties(pushDataDTO, secondPushDTO); // 使用BeanUtils复制属性
                secondPushDTO.setProduct("升船机下水");
                secondPushDTO.setDeparture("升船机");
                // 第二次推送
                sendPushRequest(secondPushDTO, visitorBO.getVisitorId());
            }
        }catch (Exception e){
            log.error("第三方门禁系统游客注册失败: {}", e.getMessage()+";"+visitorBO.getCredentialNo());
            throw new RuntimeException("推送失败");
        }
    }

    /**
     * 封装发送请求的逻辑
     */
    private void sendPushRequest(ThirdGateSystemPushDataReqDTO pushDataDTO, String visitorId) throws Exception {
        String jsonData = JsonUtils.toJsonString(pushDataDTO);

        String thirdGateSystemData = configApi.getPlatformConfigValueByKey("thirdGateSystem");
        JSONObject thirdGateSystemJson = new JSONObject(thirdGateSystemData);
        String url = thirdGateSystemJson.getStr("url");
        String staffId = thirdGateSystemJson.getStr("staffId");
        String token = thirdGateSystemJson.getStr("token");

        String sendUrl = url + "/InsertCert";
        long timestamp = System.currentTimeMillis();
        int nonce = (int) ((Math.random() * 9 + 1) * 100000);
        Map<String, String> header = new HashMap<>();
        header.put("staffid", staffId);
        header.put("timestamp", String.valueOf(timestamp));
        header.put("nonce", String.valueOf(nonce));
        header.put("signature", getSignature(String.valueOf(timestamp), String.valueOf(nonce), staffId, token, jsonData));

        log.error("实名制系统sendUrl={};jsonData={};header={}", sendUrl, jsonData, header);
        String sendResult = HttpUtil.createPost(sendUrl)
                .contentType("application/json")
                .body(jsonData)
                .headerMap(header, false)
                .timeout(15000)
                .execute()
                .body();
        log.error("insertCert 结果集={};请求参数={}", sendResult, jsonData);

        if (StrUtil.isNotBlank(sendResult)) {
            ThirdGateSystemPushDataRespDTO response = JsonUtils.parseObject(sendResult, ThirdGateSystemPushDataRespDTO.class);
            if (sendResult.contains("成功")) {
                log.error("insertCert 成功: {}", visitorId);
                tradeOrderRepositoryService.updateVis(Long.parseLong(visitorId));
            } else {
                log.error("insertCert失败 结果集={};请求参数={};response.getStatusCode()={}", sendResult, jsonData,response.getStatusCode());
                log.error("推送失败: {}, 请求参数: {}", response != null ? response.getInfo() : "", jsonData);
                throw new RuntimeException("推送失败");
            }
        }
    }

    @Override
    public void cancelCertAsync(Long refundId){
        RefundDO refundDO = tradeRefundRepositoryService.getById(refundId);
        if(refundDO==null){
            return;
        }
        if(!SellMethodEnum.isPlatSellMethod(refundDO.getSellMethod())){
            return;
        }
        //实时推送取消今天的
        List<TradeVisitorDO> visitorList = tradeRefundRepositoryService.getBoatVisitorListByRefund(refundId,DateUtil.parseDate(DateUtil.today()));
        if(CollUtil.isEmpty(visitorList)){
            return;
        }
        for (TradeVisitorDO tradeVisitorDO : visitorList) {
            SpringUtil.getBean(ThirdGateSystemService.class).cancelCert(tradeVisitorDO.getId());
        }
    }

    @Override
    public void cancelCert(Long visitorId){
        try{
            log.error("cancelCert 入参="+visitorId);
            Map param = new HashMap();
            param.put("tcid",visitorId);
            String jsonData = JsonUtils.toJsonString(param);

            String thirdGateSystemData = configApi.getPlatformConfigValueByKey("thirdGateSystem");
            JSONObject thirdGateSystemJson = new JSONObject(thirdGateSystemData);
            String url = thirdGateSystemJson.getStr("url");
            String staffId = thirdGateSystemJson.getStr("staffId");
            String token = thirdGateSystemJson.getStr("token");

            long timestamp = System.currentTimeMillis();
            int nonce = ((int) ((Math.random() * 9 + 1) * 100000));
            Map header = new HashMap<>();
            header.put("staffid",staffId);
            header.put("timestamp",timestamp+"");
            // 6位随机数
            header.put("nonce",nonce+"");
            header.put("signature",getSignature(timestamp+"",nonce+"",staffId,token,jsonData));
            String sendUrl = url + "/CancelCert";
            log.error("实名制系统sendUrl=" + sendUrl + ";jsonData=" + jsonData + ";header=" + header);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .body(jsonData)
                    .headerMap(header, false)
                    .timeout(15000)
                    .execute().body();
            log.error("CancelCert 结果集=" + sendResult + ";请求参数=" + jsonData);
            if (StrUtil.isNotBlank(sendResult)) {
                ThirdGateSystemPushDataRespDTO response = JsonUtils.parseObject(sendResult, ThirdGateSystemPushDataRespDTO.class);
                if (response != null || response.getStatusCode() == 200) {
                    //保存推送记录
                    log.error("CancelCert 成功" + visitorId);
                } else {
                    log.error("第三方门禁系统游客取消失败: {},请求参数{}", response != null ? response.getInfo() : "",jsonData);
                    //失败重发
                    throw new RuntimeException("推送失败");
                }
            }
        }catch (Exception e){
            log.error("cancelCert 异常", e);
        }
    }

    private String getSignature(String timeStamp,String nonce,String staffId, String token, String data) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //拼接签名数据
        String signStr = timeStamp + nonce + staffId + token + data;
        String sortStr = sortSign(signStr);
        String md5Val = MD5Utils.getMd5(sortStr);
        return md5Val;
    }

    private String sortSign(String signStr){
        //将字符串中字符按升序排序
        char[] chars = signStr.toCharArray();
        //将字符数组升序排列
        Arrays.sort(chars);
        String sortSign  = String.valueOf(chars);
        return sortSign;
    }
    public static final String GET = "GET";
    public static final String POST = "POST";
    private static final int CONNECT_TIMEOUT = 30000; //连接超时时间
    private static final int SOCKET_TIMEOUT = 30000; //响应超时时间
    public static String doSend(String method, String url, String postData, boolean jsonFlag,
                                Map<String, String> headers) {
        log.info("Http send:" + url + "[method:" + method + ",postData:" + postData + "]");
        CloseableHttpClient httpClient = null;
        org.apache.http.HttpResponse response = null;
        String responseData = "";
        try {
            httpClient = wrapClient(url);
            if (GET.equals(method)) {
                HttpGet request = new HttpGet(url);
                if (headers != null) {
                    for (Map.Entry<String, String> e : headers.entrySet()) {
                        request.addHeader(e.getKey(), e.getValue());
                    }
                }
                response = httpClient.execute(request);
                HttpEntity entity = response.getEntity();
                responseData = EntityUtils.toString(entity, "UTF-8");
                request.releaseConnection();
            } else if (POST.equals(method)) {
                HttpPost request = new HttpPost(url);
                if (headers != null) {
                    for (Map.Entry<String, String> e : headers.entrySet()) {
                        request.addHeader(e.getKey(), e.getValue());
                    }
                }
                StringEntity stringEntity = new StringEntity(postData == null ? "" : postData, "UTF-8");
                if (jsonFlag) {
                    stringEntity.setContentType("application/json; charset=UTF-8");
                } else {
                    stringEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
                }
                request.setEntity(stringEntity);
                response = httpClient.execute(request);
                HttpEntity entity = response.getEntity();
                responseData = EntityUtils.toString(entity, "UTF-8");
                request.releaseConnection();
            }
        } catch(ConnectTimeoutException e) {
            log.error("Http error-> http连接超时：" + url);
        } catch (Exception e) {
            log.error("Http error->" + e.getMessage());
        } finally {
            if (httpClient != null) {
                HttpClientUtils.closeQuietly(httpClient);
            }
            if (response != null) {
                HttpClientUtils.closeQuietly(response);
            }
        }
        log.info("Http response->" + responseData);
        return responseData;
    }

    private static CloseableHttpClient wrapClient(String host) {
        BasicHttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);
        HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT);
        CloseableHttpClient httpClient = new DefaultHttpClient(httpParams);
        if (host.startsWith("https://")) {
            sslClient(httpClient);
        }

        return httpClient;
    }
    private static void sslClient(CloseableHttpClient httpClient) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] xcs, String str) {

                }

                public void checkServerTrusted(X509Certificate[] xcs, String str) {

                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = httpClient.getConnectionManager();
            SchemeRegistry registry = ccm.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
    public static void main(String[] args) {

//        System.out.println(IdcardUtil.getGenderByIdCard("SGP420575091905"));
        System.out.println(IdcardUtil.getGenderByIdCard("942702197509190017"));
//        String url = "http://202.103.6.158:10099/api/Order";
//        String staffId = "TC001";
//        String token = "54807262-fe2c-4ca4-9443-5e411efb3e7d";
//        ThirdGateSystemPushDataReqDTO pushDataDTO = new ThirdGateSystemPushDataReqDTO();
//        pushDataDTO.setTcid("1872109474495037444");
//        pushDataDTO.setTripdate("2025-12-26");
//        pushDataDTO.setProduct("两坝一峡下水-两坝一峡下水【车去船回】");
//        pushDataDTO.setTripmode("两坝一峡下水-两坝一峡下水【车去船回】");
//        //1 豪华游轮 0两坝一峡 2兼
//        pushDataDTO.setDeparture("2");
//        pushDataDTO.setTickettype("两坝一峡下水-两坝一峡下水【车去船回】");
//        pushDataDTO.setCerttype("身份证");
//        pushDataDTO.setName("qsl");
//        pushDataDTO.setSex("男");
//        pushDataDTO.setCert("513021199010255070");
//        String jsonData = JsonUtils.toJsonString(pushDataDTO);
//
//        String sendUrl = url+"/InsertCert";
//        long timestamp = System.currentTimeMillis();
//        int nonce = ((int) ((Math.random() * 9 + 1) * 100000));
//        Map header = new HashMap<>();
//        header.put("staffid",staffId);
//        header.put("timestamp",timestamp+"");
//        // 6位随机数
//        header.put("nonce",nonce+"");
//
//        String signStr = timestamp + nonce + staffId + token + jsonData;
//
//
//        //将字符串中字符按升序排序
//        char[] chars = signStr.toCharArray();
//        //将字符数组升序排列
//        Arrays.sort(chars);
//        String sortSign  = String.valueOf(chars);
//        String md5Val = MD5Util.md5Upper(sortSign);
//        header.put("signature",md5Val);
//        log.error("实名制系统sendUrl="+ sendUrl+";jsonData="+jsonData+";header="+header);
////        String sendResult = HttpUtil.createPost("http://202.103.6.158:10099/api/Order/InsertCert").contentType("application/json")
////                .body(jsonData)
////                .headerMap(header, false)
////                .timeout(15000)
////                .execute().body();
//        String sendResult = doSend(POST,url+"/InsertCert",jsonData,true,header);
//
//        log.error("insertCert 结果集="+ sendResult);
    }


}
