package com.jsowell.thirdparty.platform.service;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Maps;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.JWTUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.dto.nanrui.PushAlarmInfoDTO;
import com.jsowell.pile.dto.ningxiajiaotou.NXJTQueryStationInfoDTO;
import com.jsowell.pile.thirdparty.CommonParamsDTO;
import com.jsowell.pile.vo.ThirdPartySecretInfoVO;
import com.jsowell.thirdparty.lianlian.vo.AccessTokenVO;
import com.jsowell.thirdparty.lianlian.vo.LianLianResultVO;
import com.jsowell.thirdparty.platform.dto.QueryOrderDTO;
import com.jsowell.thirdparty.platform.util.Cryptos;
import com.jsowell.thirdparty.platform.util.Encodes;
import com.jsowell.thirdparty.platform.util.GBSignUtils;
import org.bouncycastle.crypto.CryptoException;
import org.springframework.beans.factory.InitializingBean;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.*;

/**
 * 第三方平台对接需要的api集合
 * 说明：此接口中的方法可以选择性实现，具体看要对接的第三方平台需要什么方法
 *      所有的方法默认抛出未实现异常，在三方平台实现类中未覆盖的话，掉用会抛异常，注意处理异常
 */
public interface ThirdPartyPlatformService extends InitializingBean {
    default void printServiceName() {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * query_token 获取token，提供给第三方平台使用
     * @param dto
     * @return
     */
    default Map<String, String> queryToken(CommonParamsDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    // default Map<String, String> queryToken(String operatorId, String operatorSecret) {
    //     throw new UnsupportedOperationException("This method is not yet implemented");
    // }

    // =================================================================================== //
    // ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓  由我方平台实现此接口，对方平台调用的查询接口 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ //
    // =================================================================================== //

    /**
     * 查询运营商信息 query_operator_info
     * supervise_query_operator_info
     *
     * @param dto 查询运营商信息DTO
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryOperatorInfo(QueryOperatorInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 查询充电站信息 query_stations_info
     * 此接口用于查询对接平台的充电站的信息
     *
     * @param dto 查询站点信息dto
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryStationsInfo(QueryStationInfoDTO dto){
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 设备接口状态查询 query_station_status
     *
     * @param dto 查询站点信息dto
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryStationStatus(QueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 查询统计信息 query_station_stats
     *
     * @param dto 查询站点信息dto
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryStationStats(QueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 查询充电电量信息 query_order_info
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryOrderInfo(QueryOrderDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 请求设备认证  query_equip_auth
     * 业务信息交换
     *
     * @param dto 联联平台请求设备认证
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryEquipAuth(QueryEquipmentDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 请求启动充电  query_start_charge
     *
     * @param dto 请求启动充电DTO
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryStartCharge(QueryStartChargeDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 查询充电状态 query_equip_charge_status
     *
     * @param dto 查询充电状态DTO
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryEquipChargeStatus(QueryEquipChargeStatusDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 请求停止充电 query_stop_charge
     *
     * @param dto 请求启动充电DTO
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryStopCharge(QueryStartChargeDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 充电站内充电桩空闲状态查询 query_free_pile_number
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryFreePileNumber(NXJTQueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 某车牌号消费记录查询 query_orders_info_by_Plate_number
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryOrdersInfoByPlateNumber(NXJTQueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 某段时间内消费记录查询 query_orders_info
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryOrdersInfo(NXJTQueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 过程信息查询  query_bms_info
     * @param pileConnectorCode
     * @return
     */
    default Map<String, String> queryBmsInfo(String pileConnectorCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 查询业务策略信息结果
     * 请求计费策略 request_equip_business_policy
     *
     * @param dto 请求启动充电DTO
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> queryEquipBusinessPolicy(QueryStartChargeDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * VIN码充电 insert_start_charge
     * 华为平台
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> insertStartCharge(QueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 下发计费策略响应 notification_deliver_equip_business_policy_result
     * 华为平台
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default Map<String, String> notificationDeliverEquipBusinessPolicyResult(QueryStationInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }


    // =================================================================================== //
    // ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 由对方平台实现此接口，我方平台调用的通知接口  ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ //
    // =================================================================================== //

    /**
     * 过程信息推送 notification_bmsInfo
     * 当运营商平台有充放电电池数据过程信息时，推送最新的信息通知到市级监控平台
     * @param pileConnectorCode
     * @return
     */
    default String notificationBMSInfo(String pileConnectorCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 充电站信息变化推送 notification_stationInfo
     * 新站需要推送。当站点信息发生变化时，推送新的信息通知到市级平台
     *
     * @param stationId 充电站id
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStationInfo(String stationId) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 设备状态变化推送
     * 概述：当设备状态发生变化时，推送最新的状态到合作方
     * 接口定义：
     * 中电联平台 设备状态变化推送 notification_stationStatus
     * 内蒙古平台 推送充电设备接口状态信息 supervise_notification_station_status
     *
     * @param dto
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStationStatus(PushRealTimeInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 设备状态变化推送
     * 概述：当设备状态发生变化时，推送最新的状态到合作方
     * 接口定义：
     * 中电联平台 设备状态变化推送 notification_stationStatus
     * 内蒙古平台 推送充电设备接口状态信息 supervise_notification_station_status
     *
     * @param stationId 站点id
     * @param pileConnectorCode 充电桩枪口编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStationStatus(String stationId, String pileConnectorCode, String status, ThirdPartySecretInfoVO secretInfoVO) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 设备充电中状态变化推送 notification_connector_charge_status
     *
     * @param orderCode 订单编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationConnectorChargeStatus(String orderCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    default String notificationConnectorChargeStatus(String orderCode, ThirdPartySecretInfoVO secretInfoVO) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 站点费率变化推送 notification_stationFee
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStationFee(String stationId) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }
    default String notificationStationFee(String stationId, ThirdPartySecretInfoVO secretInfoVO) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 充电订单推送 notification_charge_order_info/notification_orderInfo
     *
     * @param orderCode 订单编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationChargeOrderInfo(String orderCode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, CryptoException {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    default String notificationChargeOrderInfo(String orderCode, ThirdPartySecretInfoVO secretInfoVO) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 告警信息推送 notification_alarmInfo
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationAlarmInfo(PushAlarmInfoDTO dto) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送启动充电结果 notification_start_charge_result
     *
     * @param orderCode 订单编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStartChargeResult(String orderCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送充电状态 notification_equip_charge_status
     * 推送充电状态信息 supervise_notification_equip_charge_status
     *
     * @param orderCode 订单编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationEquipChargeStatus(String orderCode)  {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送停止充电结果  notification_stop_charge_result
     *
     * @param orderCode 订单编号
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationStopChargeResult(String orderCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 华为平台
     * 平台充电设备编码同步 notification_operation_system_info
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationOperationSystemInfo(String orderCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送充换电站用能统计信息 supervise_notification_operation_stats_info
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationOperationStatsInfo(String stationId) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送充电站历史充电订单信息 supervise_notification_charge_order_info_history
     *
     * @throws UnsupportedOperationException 未实现异常
     */
    default String notificationChargeOrderInfoHistory(String orderCode) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送订单结算信息 notification_order_settlement_info
     */
    default Map<String, String> notificationOrderSettlementInfo(PushOrderSettlementDTO order) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    /**
     * 推送充换电站实时功率
     * @param stationIds
     * @return
     */
    default String notificationPowerInfo(List<String> stationIds) {
        throw new UnsupportedOperationException("This method is not yet implemented");
    }

    // -------------------------------------- 以下是公用方法 --------------------------------------- //
    /**
     * 从联联平台获取令牌
     *
     * @param operatorId 运营商id
     * @param operatorSecret
     * @return
     */
    default String getToken(String urlAddress, String operatorId, String operatorSecret,
                              String dataSecretIv, String signSecret, String dataSecret) {
        String token = "";
        try {
            // 请求地址
            String requestUrl = urlAddress + "query_token";

            // 请求data
            Map<String, String> data = new HashMap<>();
            data.put("OperatorID", operatorId);
            data.put("OperatorSecret", operatorSecret);
            data.put("DataSecretIV", dataSecretIv);
            String dataJson = JSONUtil.toJsonStr(data);

            // 加密
            byte[] encryptText = Cryptos.aesEncrypt(dataJson.getBytes(StandardCharsets.UTF_8),
                    dataSecret.getBytes(), dataSecretIv.getBytes());
            String strData = Encodes.encodeBase64(encryptText);

            Map<String, String> request = new LinkedHashMap<>();
            request.put("OperatorID", operatorId);
            request.put("Data", strData);
            request.put("TimeStamp", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date()));
            request.put("Seq", "0001");

            // 生成签名
            String sig = GBSignUtils.sign(request, signSecret);
            request.put("Sig", sig);

            String tokenRequest = JSONUtil.toJsonStr(request);

            String response = HttpUtil.post(requestUrl, tokenRequest);
            LianLianResultVO result = JSON.parseObject(response, LianLianResultVO.class);
            // logger.info("获取令牌 result:{}", result);

            if (result.getRet() == 0) {
                // 解密data
                byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64((String) result.getData()),
                        dataSecret.getBytes(), dataSecretIv.getBytes());
                String dataStr = new String(plainText, StandardCharsets.UTF_8);
                Map<String, String> resultMap = (Map<String, String>) JSON.parse(dataStr);
                token = resultMap.get("AccessToken");
                // logger.info("token: {}", token);
            }
            // logger.info("获取令牌 result:{}, token: {}", result, token);
        } catch (Exception e) {
            return token;
        }
        return token;
    }

    // =================================================================================== //
    // ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 不同平台都可以使用的公共方法 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ //
    // =================================================================================== //

    /**
     * 给第三方平台生成token
     */
    default Map<String, String> generateToken(String operatorSecret, String dataSecret, String dataSecretIv,
                                              String signSecret, String operatorId, String data) {
        // 解密data
        byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(data), dataSecret.getBytes(), dataSecretIv.getBytes());
        String dataStr = new String(plainText, StandardCharsets.UTF_8);
        Map<String, String> resMap = (Map<String, String>) JSON.parse(dataStr);
        String secret = resMap.get("OperatorSecret");

        // 对比解出来的密钥是否和数据库中保存的一致
        if (!StringUtils.equals(operatorSecret, secret)) {
            // System.out.println("密钥不一致");
            return null;
        }
        // System.out.println("密钥校验通过!!  密钥为: " + operatorSecret);

        long ttlMillis = 60 * 60 * 24 * 1000;
        String token = JWTUtils.createToken(operatorId, operatorSecret, ttlMillis);
        // System.out.println("生成的token：" + token);

        // 组装返回参数
        AccessTokenVO vo = new AccessTokenVO();
        vo.setAccessToken(token);
        vo.setOperatorID(operatorId);
        vo.setTokenAvailableTime((int) (ttlMillis / 1000));
        vo.setFailReason(0);
        vo.setSuccStat(0);

        Map<String, String> resultMap = Maps.newLinkedHashMap();
        // 加密数据
        // byte[] encryptText = Cryptos.aesEncrypt(JSON.toJSONString(vo).getBytes(),
        //         dataSecret.getBytes(), dataSecretIv.getBytes());
        // String encryptData = Encodes.encodeBase64(encryptText);
        String encryptData = Cryptos.aesEncrypt(JSON.toJSONString(vo), dataSecret, dataSecretIv);

        resultMap.put("Data", encryptData);
        // 生成sig
        String resultSign = GBSignUtils.sign(resultMap, signSecret);
        resultMap.put("Sig", resultSign);

        return resultMap;
    }

    /**
     * 校验签名
     * @param operatorID 平台标识 组织机构代码
     * @param data 参数内容
     * @param timeStamp 时间戳
     * @param seq 自增序列
     * @param sig 数字签名
     * @param signSecret 签名密钥
     * @return 校验结果
     */
    default boolean verifySignature(CommonParamsDTO dto, String signSecret) {
        Map<String, String> map = Maps.newLinkedHashMap();
        map.put("OperatorID", dto.getOperatorID());
        map.put("Data", dto.getData());
        map.put("TimeStamp", dto.getTimeStamp());
        map.put("Seq", dto.getSeq());
        String sign = GBSignUtils.sign(map, signSecret);

        // 验证签名 得到请求方传过来的签名sig->自己拿到请求体后，再按双方约定的协议生成一个sig->对比两个sig是否一致
        return StringUtils.equals(dto.getSig(), sign);
    }


}
