package com.yc.ship.module.trade.service.contract;

import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONUtil;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.trade.api.contract.dto.ContractResponseBody;
import com.yc.ship.module.trade.api.contract.dto.InvokeResponse;
import com.yc.ship.module.trade.api.contract.dto.QueryContractRespDTO;
import com.yc.ship.module.trade.api.contract.dto.QueryContractResponse;
import com.yc.ship.module.trade.enums.InvokeContractCodeEnum;
import com.yc.ship.module.trade.service.contract.bo.ContractApplyReqBO;
import com.yc.ship.module.trade.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;
import java.util.HashMap;

/**
 * @author qsl
 * @description todo
 * @date 2025/6/18 16:37
 */
@Slf4j
@Service
@Validated
public class ContractCommonServiceImpl implements ContractCommonService {

    private String contractApplyUrl="/v1/econtract/apply";


    private String invalidateContractUrl="/v1/econtract/invalidate/";


    private String contractResendSmsUrl="/v1/econtract/resend/";


    private String contractQueryUrl="/v1/econtract/";


    private String contractQueryStatusUrl = "/v1/econtract/status/";


    RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());

    @Resource
    private ConfigApi configApi;

    public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
        @Override
        protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
            try {
                if (!(connection instanceof HttpsURLConnection)) {
                    throw new RuntimeException("An instance of HttpsURLConnection is expected");
                }

                HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
                TrustManager[] trustAllCerts = new TrustManager[]{
                        new X509TrustManager() {
                            @Override
                            public X509Certificate[] getAcceptedIssuers() {
                                return null;
                            }
                            @Override
                            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                            }
                            @Override
                            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                            }
                        }
                };
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));

                httpsConnection.setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                });

                super.prepareConnection(httpsConnection, httpMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        private class MyCustomSSLSocketFactory extends SSLSocketFactory {
            private final SSLSocketFactory delegate;
            public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
                this.delegate = delegate;
            }

            // 返回默认启用的密码套件。除非一个列表启用，对SSL连接的握手会使用这些密码套件。
            // 这些默认的服务的最低质量要求保密保护和服务器身份验证
            @Override
            public String[] getDefaultCipherSuites() {
                return delegate.getDefaultCipherSuites();
            }

            // 返回的密码套件可用于SSL连接启用的名字
            @Override
            public String[] getSupportedCipherSuites() {
                return delegate.getSupportedCipherSuites();
            }

            @Override
            public Socket createSocket(final Socket socket, final String host, final int port,
                                       final boolean autoClose) throws IOException {
                final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
                return overrideProtocol(underlyingSocket);
            }

            @Override
            public Socket createSocket(final String host, final int port) throws IOException {
                final Socket underlyingSocket = delegate.createSocket(host, port);
                return overrideProtocol(underlyingSocket);
            }

            @Override
            public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                                       final int localPort) throws
                    IOException {
                final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
                return overrideProtocol(underlyingSocket);
            }

            @Override
            public Socket createSocket(final InetAddress host, final int port) throws IOException {
                final Socket underlyingSocket = delegate.createSocket(host, port);
                return overrideProtocol(underlyingSocket);
            }

            @Override
            public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                                       final int localPort) throws
                    IOException {
                final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
                return overrideProtocol(underlyingSocket);
            }

            private Socket overrideProtocol(final Socket socket) {
                if (!(socket instanceof SSLSocket)) {
                    throw new RuntimeException("An instance of SSLSocket is expected");
                }
                //((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2"});
                ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"});
                return socket;
            }
        }
    }

    @Override
    public QueryContractResponse applyContract(ContractApplyReqBO request) {
        try {
            HashMap<String, Object> map = new HashMap<>();
            map.put("ERPContractId", request.getERPContractId());
            map.put("authType", 0);
            map.put("templateId", request.getTemplateId());
            map.put("callbackURL", configApi.getConfigValueByKey("contract.callbackUrl"));
            map.put("travelAgency", request.getTravelAgency());
            map.put("itinerary", request.getItinerary());
            map.put("touristsInfo", request.getTouristsInfo());
            map.put("signatory", request.getSignatory());
            map.put("cost", request.getCost());
            map.put("insurance", request.getInsurance());
            map.put("dispute", request.getDispute());
            map.put("groupAgreement", request.getGroupAgreement());
            HttpHeaders headers = getContractHeaders();
            HttpEntity httpEntity = new HttpEntity(map, headers);
            String url = configApi.getConfigValueByKey("contract.url") + contractApplyUrl;
            log.error("电子合同请求参数:{}",url+";"+map.toString()+";"+headers.toString());
            ResponseEntity<QueryContractResponse> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, QueryContractResponse.class);
            log.error("电子合同返回数据:{}",JSONUtil.toJsonStr(exchange.getBody()));
            return exchange.getBody();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用第三方合同平台【合同作废】接口失败", e);
        }
        return null;
    }

    @Override
    public InvokeResponse invalidateContract(String contractNumber) {
        try {
            InvokeResponse response = new InvokeResponse();
            HttpHeaders headers = getContractHeaders();
            HttpEntity httpEntity = new HttpEntity(headers);
            String invalidateContractUrl = configApi.getConfigValueByKey("contract.url") + this.invalidateContractUrl + contractNumber;
            ResponseEntity<ContractResponseBody> exchange = restTemplate.exchange(invalidateContractUrl, HttpMethod.POST, httpEntity, ContractResponseBody.class);
            if (exchange != null && exchange.getBody() != null) {
                if (exchange.getBody().getData() != null && StringUtils.isNotBlank(exchange.getBody().getData().getState())) {
                    response.setCode(InvokeContractCodeEnum.SUCCESS.getCode());
                    response.setMessage(InvokeContractCodeEnum.SUCCESS.getDesc());

                    return response;
                }
            }
            if (exchange.getBody().getError() != null && StringUtils.isNotBlank(exchange.getBody().getError().getMessage())) {
                response.setCode(InvokeContractCodeEnum.ERROR.getCode());
                response.setMessage(exchange.getBody().getError().getMessage());

                return response;
            }
        }catch (Exception e) {
            log.error("调用第三方合同平台【合同作废】接口失败", e);
        }

        return new InvokeResponse(InvokeContractCodeEnum.ERROR.getCode(), InvokeContractCodeEnum.ERROR.getDesc());
    }

    @Override
    public boolean sendContractSms(String contractNumber, String mobile) {
        try {
            HashMap<String, Object> map = new HashMap<>();
            map.put("phone", mobile);
            HttpHeaders headers = getContractHeaders();
            HttpEntity httpEntity = new HttpEntity(map, headers);
            String resendSmsUrl = configApi.getConfigValueByKey("contract.url") + contractResendSmsUrl;
            ResponseEntity<ContractResponseBody> exchange = restTemplate.exchange(resendSmsUrl, HttpMethod.POST, httpEntity, ContractResponseBody.class);
            if (exchange != null && exchange.getBody() != null){
                if (exchange.getBody().getData() != null && StringUtils.isNotBlank(exchange.getBody().getData().getState())
                        && exchange.getBody().getData().getState().equals(InvokeContractCodeEnum.SUCCESS.getMsg())){
                    return true;
                }
            }
        }catch (Exception e){
            log.error("调用第三方合同平台【发送合同短信】接口失败", e);
        }

        return false;
    }

    @Override
    public QueryContractRespDTO queryContract(String contractNumber) {
        log.info("调用ThirdContractService.queryContract方法成功，合同编号：{}", contractNumber);
        try {
            HttpHeaders headers = getContractHeaders();
            HttpEntity httpEntity = new HttpEntity(headers);
            String queryContractUrl = configApi.getConfigValueByKey("contract.url") + contractQueryUrl + contractNumber;
            ResponseEntity<QueryContractResponse> exchange = restTemplate.exchange(queryContractUrl, HttpMethod.GET, httpEntity, QueryContractResponse.class);
            log.error("电子合同查询成功："+JSONUtil.parseObj(exchange.getBody()));
            if (exchange.getBody() != null && exchange.getBody().getData() != null) {
                QueryContractRespDTO response = exchange.getBody().getData();
                return response;
            }
        }catch (Exception e){
            log.error("调用第三方合同平台【合同查询】接口失败", e);
        }

        return null;
    }

    @Override
    public Integer queryContractStatus(String contractNumber) {
        try {
            HttpHeaders headers = getContractHeaders();
            HttpEntity httpEntity = new HttpEntity(headers);
            String queryContractUrl = configApi.getConfigValueByKey("contract.url") + contractQueryStatusUrl + contractNumber;
            ResponseEntity<ContractResponseBody> exchange = restTemplate.exchange(queryContractUrl, HttpMethod.GET, httpEntity, ContractResponseBody.class);
            if (exchange != null && exchange.getBody() != null && exchange.getBody().getData() != null
                    && StringUtils.isNotBlank(exchange.getBody().getData().getState())){
                Integer state = Integer.valueOf(exchange.getBody().getData().getState());

                return state;
            }
        }catch (Exception e) {
            log.error("调用第三方合同平台【合同状态查询】接口失败", e);
        }

        return null;
    }

    public HttpHeaders getContractHeaders() throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("x-12301-source", configApi.getConfigValueByKey("contract.appid")); //分配给ERP的appId
        headers.set("x-12301-key", configApi.getConfigValueByKey("contract.appid")); //分配给旅行社的appId。
        headers.set("x-12301-version", configApi.getConfigValueByKey("contract.version"));//填写应用的版本号信息，1.1.1。
        long millis = System.currentTimeMillis();
        headers.set("x-12301-timestamp", String.valueOf(millis)); //时间戳
        String sign = configApi.getConfigValueByKey("contract.signKey") + millis;
        String encode = Base64.encode(SecurityUtils.md5Sign(sign));
        headers.set("x-12301-signature", encode); //根据协议规定的签名字符串签名
        return headers;
    }
}
