package com.friday.tooldriver.service.rpa.supplier.smartrpa;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.friday.base.common.response.DubboResult;
import com.friday.operation.api.keepalive.constant.taieoc.TaieOcConstants;
import com.friday.operation.api.keepalive.dto.smartrpa.*;
import com.friday.operation.api.keepalive.dto.taieoc.MachineLicenseFilterDto;
import com.friday.operation.api.tooldriver.constant.DriverConstant;
import com.friday.operation.api.tooldriver.service.ILicense;
import com.friday.tooldriver.constants.TaieOcManageCode;
import com.friday.tooldriver.dto.smartrpa.SmartRobotDto;
import com.friday.tooldriver.mapper.taieoc.MachineLicenseMapper;
import com.friday.tooldriver.po.taieoc.MachineLicensePo;
import com.friday.tooldriver.utils.DESUtils;
import com.friday.tooldriver.utils.SM2Utils;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class LicenseManager implements ILicense {

    @Autowired
    private RobotManager robotManager;
    @Autowired
    private MachineLicenseMapper machineLicenseMapper;
    @Value("${license.expire.date}")
    private Integer licenseExpireDate;
    private static final Gson gson = new Gson();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DubboResult<MachineLicenseRespDto> getLicense(MachineLicenseAcquireReqDto reqDto) {
        // 根据机器信息判定是否需要登录
//        DubboResult<MachineLicenseRespDto> result;
        try {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.YEAR, licenseExpireDate);
//          时间戳毫秒设置为零，对应处理入库时间预防 秒级四舍五入情况，导致入库时间+1s，导致rpa登录校验失败
            cal.set(Calendar.MILLISECOND, 0); //毫秒
            SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
            DubboResult<SmartRobotDto> smartRobotResult = robotManager.queryRobotByKey(reqDto.getMachineCode() + reqDto.getUser());
            if (!smartRobotResult.success()) {
                return DubboResult.newFailure(smartRobotResult.getCode(), smartRobotResult.getMessage());
            }
            // 先判断是否获取过license信息
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
                    .machineKey(reqDto.getMachineCode() + reqDto.getUser())
                    .licenseType(reqDto.getLicenseType())
                    .machineType(reqDto.getMachineType())
                    .requestParam(reqDto.getParamsMap() == null ? TaieOcConstants.EMPTY_STRING : gson.toJson(reqDto.getParamsMap()))
                    .build());
            if (CollectionUtils.isNotEmpty(machineLicensePos)) {
                return DubboResult.newSuccess(machineLicensePos.get(0).createRespDto(smartRobotResult.getObject().getAuthState()));
            } else {
                return DubboResult.newFailure(TaieOcManageCode.LICENSE_NOT_EXIST.getCode(), "license许可信息不存在,未查询到有效许可数据");
            }
            // 获取license信息
//            Date endTime = cal.getTime();
//            String license = SM2Utils.generateLicense(reqDto.getLicenseType(), reqDto.getMachineType()
//                    , sdf.format(endTime), reqDto.getParamsMap());
            // license申请信息落库
//            MachineLicensePo licensePo = MachineLicensePo.builder()
//                    .license(license)
//                    .machineKey(reqDto.getMachineCode() + reqDto.getUser())
//                    .machineType(reqDto.getMachineType())
//                    .requestParam(reqDto.getParamsMap() == null ? TaieOcConstants.EMPTY_STRING : gson.toJson(reqDto.getParamsMap()))
//                    .startTime(Calendar.getInstance().getTime())
//                    .endTime(endTime)
//                    .licenseType(reqDto.getLicenseType())
//                    .build();
//            machineLicenseMapper.insert(licensePo);
//            result = DubboResult.newSuccess(MachineLicenseRespDto.builder()
//                    .license(license)
//                    .licenseType(reqDto.getLicenseType())
//                    .authState(smartRobotResult.getObject().getAuthState())
//                    .expireTime(sdf.format(endTime))
//                    .build());
//            return result;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return DubboResult.newFailure(TaieOcManageCode.LICENSE_AQUIRE.getCode(), TaieOcManageCode.LICENSE_AQUIRE.getMessage());
        }


    }


    @Override
    public DubboResult<Boolean> verifyLicense(MachineLicenseAuthReqDto dto) {
        DubboResult<Boolean> result;
        log.info("校验license, 入参为：" + gson.toJson(dto));
        SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
        try {
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
                    .machineLicense(dto.getLicense())
                    .licenseType(dto.getLicenseType())
                    .machineType(dto.getMachineType())
                    .build());
            boolean match = machineLicensePos.stream().anyMatch(f ->
            {
                try {
                    return SM2Utils.verifyMachineLicense(dto.getLicense(), dto.getLicenseType(),
                            dto.getMachineType(),
                            sdf.format(f.getEndTime()), f.getRequestParam()
                    );
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            log.info("校验license, 结果为：" + gson.toJson(match));
            result = DubboResult.newSuccess(match);
            result.setMessage(TaieOcManageCode.SUCCESS.getMessage());
            return result;
        } catch (Exception e) {
            log.error(TaieOcManageCode.INTERNAL_ERROR.toString(e.getMessage()), e);
            return DubboResult.newFailure(TaieOcManageCode.INTERNAL_ERROR.getCode(), TaieOcManageCode.INTERNAL_ERROR.getMessage());
        }
    }

    /**
     * 根据license信息判断是否需要登录认证
     *
     * @param license
     * @return
     */
    @Override
    public DubboResult<Boolean> verifyLoginState(String license) {
        DubboResult<Boolean> result;
        try {
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
                    .machineLicense(license)
                    .build());
            if (CollectionUtils.isEmpty(machineLicensePos)) {
                return DubboResult.newFailure(TaieOcManageCode.LICENSE_NOT_EXIST.getCode(), TaieOcManageCode.LICENSE_NOT_EXIST.getMessage());
            }
            Boolean res = machineLicensePos.stream().allMatch(f -> {
                try {
                    return queryMachineLoginState(f);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            result = DubboResult.newSuccess(res);
            result.setMessage(TaieOcManageCode.SUCCESS.getMessage());
            return result;
        } catch (Exception e) {
            return DubboResult.newFailure(TaieOcManageCode.FAIL.getCode(), TaieOcManageCode.FAIL.getMessage());
        }
    }

    private Boolean queryMachineLoginState(MachineLicensePo po) throws Exception {
        DubboResult<SmartRobotDto> smartRobotDtoDubboResult = robotManager.queryRobotByKey(po.getMachineKey());
        if (!smartRobotDtoDubboResult.success()) {
            throw new Exception(smartRobotDtoDubboResult.getMessage());
        }
        SmartRobotDto smartRobotDto = smartRobotDtoDubboResult.getObject();
        return StringUtils.equals(smartRobotDto.getAuthState(), DriverConstant.NO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public DubboResult<MachineLicenseRespDto> getExistLicenseOnly(MachineLicenseAcquireReqDto reqDto) {
        // 根据机器信息判定是否需要登录
        DubboResult<MachineLicenseRespDto> result;
        try {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.YEAR, licenseExpireDate);
//          时间戳毫秒设置为零，对应处理入库时间预防 秒级四舍五入情况，导致入库时间+1s，导致rpa登录校验失败
            cal.set(Calendar.MILLISECOND, 0); //毫秒
            SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
            DubboResult<SmartRobotDto> smartRobotResult = robotManager.queryRobotByKey(reqDto.getMachineCode() + reqDto.getUser());
            if (!smartRobotResult.success()) {
                return DubboResult.newFailure(smartRobotResult.getCode(), smartRobotResult.getMessage());
            }
            // 先判断是否获取过license信息
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
                    .machineKey(reqDto.getMachineCode() + reqDto.getUser())
                    .licenseType(reqDto.getLicenseType())
                    .machineType(reqDto.getMachineType())
                    .requestParam(reqDto.getParamsMap() == null ? TaieOcConstants.EMPTY_STRING : gson.toJson(reqDto.getParamsMap()))
                    .build());
            if (CollectionUtils.isNotEmpty(machineLicensePos)) {
                return DubboResult.newSuccess(machineLicensePos.get(0).createRespDto(smartRobotResult.getObject().getAuthState()));
            } else {
                return DubboResult.newFailure(null, "未查询到对应类型许可数据,许可获取失败");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return DubboResult.newFailure(TaieOcManageCode.LICENSE_AQUIRE.getCode(), TaieOcManageCode.LICENSE_AQUIRE.getMessage());
        }


    }


    @Transactional(rollbackFor = Exception.class)
    public DubboResult<MachineLicenseRespDto> createLicense(MachineLicenseAcquireReqDto reqDto) {
        // 根据机器信息判定是否需要登录
        DubboResult<MachineLicenseRespDto> result;
        try {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.YEAR, licenseExpireDate);
//          时间戳毫秒设置为零，对应处理入库时间预防 秒级四舍五入情况，导致入库时间+1s，导致rpa登录校验失败
            cal.set(Calendar.MILLISECOND, 0); //毫秒
            SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
            DubboResult<SmartRobotDto> smartRobotResult = robotManager.queryRobotByKey(reqDto.getMachineCode() + reqDto.getUser());
            if (!smartRobotResult.success()) {
                return DubboResult.newFailure(smartRobotResult.getCode(), smartRobotResult.getMessage());
            }
            // 先判断是否获取过license信息
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
                    .machineKey(reqDto.getMachineCode() + reqDto.getUser())
                    .licenseType(reqDto.getLicenseType())
                    .machineType(reqDto.getMachineType())
                    .requestParam(reqDto.getParamsMap() == null ? TaieOcConstants.EMPTY_STRING : gson.toJson(reqDto.getParamsMap()))
                    .build());
            if (CollectionUtils.isNotEmpty(machineLicensePos)) {
                return DubboResult.newSuccess(machineLicensePos.get(0).createRespDto(smartRobotResult.getObject().getAuthState()));
            }
            // 获取license信息
            Date endTime = cal.getTime();
            String license = SM2Utils.generateLicense(reqDto.getLicenseType(), reqDto.getMachineType()
                    , sdf.format(endTime), reqDto.getParamsMap());

            // license申请信息落库
            MachineLicensePo licensePo = MachineLicensePo.builder()
                    .license(license)
                    .machineKey(reqDto.getMachineCode() + reqDto.getUser())
                    .machineType(reqDto.getMachineType())
                    .requestParam(reqDto.getParamsMap() == null ? TaieOcConstants.EMPTY_STRING : gson.toJson(reqDto.getParamsMap()))
                    .startTime(Calendar.getInstance().getTime())
                    .endTime(endTime)
                    .licenseType(reqDto.getLicenseType())
                    .build();
            machineLicenseMapper.insert(licensePo);
            log.info("入库许可数据信息：" + licensePo);
            result = DubboResult.newSuccess(MachineLicenseRespDto.builder()
                    .license(license)
                    .licenseType(reqDto.getLicenseType())
                    .authState(smartRobotResult.getObject().getAuthState())
                    .expireTime(sdf.format(endTime))
                    .build());
            return result;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return DubboResult.newFailure(TaieOcManageCode.LICENSE_AQUIRE.getCode(), TaieOcManageCode.LICENSE_AQUIRE.getMessage());
        }
    }


    @Override
    public DubboResult<Integer> updateMachineLicense(MachineLicenseAuthUpdateDto req) {

        String allLicense = req.getAllLicense();
        String one = allLicense.split("%%&&")[0];
        String two = allLicense.split("%%&&")[1];
        int usedTimes = machineLicenseMapper.checkLicenseIsUsed(one);
        if (usedTimes > 0) {
            return DubboResult.newFailure("更新许可失败", "该许可码已绑定机器，请勿重复使用");
        }

        req.setLicenseType(req.getRobotKey());
        req.setMachineType("ALL");

        req.setLicense(one);
        req.setRobotNumLicense(two);
        req.setMachineKey(req.getRobotKey());
        Date date = dateTime(one);
        int i = machineLicenseMapper.checkExistByRobotKey(req.getRobotKey());
        if (date != null) {
            req.setEndTime(date);
        }
        req.setStartTime(new Date());
        if (i == 0) {
//            当前不存在使用中的license， 许可已过期或者不存在
//            新增许可
            int result = machineLicenseMapper.insertLicenseAll(req);
            return DubboResult.newSuccess("成功", result);
        } else {
//            当前不存在使用中的license
//            更新许可
            int result = machineLicenseMapper.updateMachineLicense(req);
            return DubboResult.newSuccess("成功", result);
        }

    }

    @Override
    public DubboResult<MachineLicenseInfo> getRobotLicenseInfo(MachineLicenseInfoReq req) {
        MachineLicenseInfo respDto = machineLicenseMapper.selectMachineLicenseInfo(req);
        if (respDto != null && StringUtils.isNotEmpty(respDto.getRobotNumLicense())) {
            String number = DESUtils.decrypt(respDto.getRobotNumLicense(), DESUtils.SECRET_KEY);
            respDto.setRobotNum(number);
        }
        return DubboResult.newSuccess("成功", respDto);
    }

    @Override
    public DubboResult<Boolean> checkRobotLicenseTime(MachineLicenseAuthUpdateDto dto) {
        DubboResult<Boolean> result;
        log.info("开始校验机器工位license, 机器识别码为：" + gson.toJson(dto));
        SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
        try {
            List<MachineLicensePo> machineLicensePos = machineLicenseMapper.selectMachineLicense(MachineLicenseFilterDto.MachineLicenseFilterBuilder()
//                    .machineLicense(dto.getLicense())
                    .machineKey(dto.getMachineKey())
                    .build());
            log.info("根据机器识别码，对应license如下：" + gson.toJson(machineLicensePos));
            boolean match = machineLicensePos.stream().anyMatch(f ->
            {
                try {
                    return SM2Utils.verifyMachineLicense(f.getLicense(), f.getLicenseType(),
                            f.getMachineType(),
                            sdf.format(f.getEndTime()), f.getRequestParam()
                    );
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            log.info("校验license, 结果为：" + gson.toJson(match));
            result = DubboResult.newSuccess(match);
            result.setMessage(TaieOcManageCode.SUCCESS.getMessage());
            return result;
        } catch (Exception e) {
            log.error(TaieOcManageCode.INTERNAL_ERROR.toString(e.getMessage()), e);
            return DubboResult.newFailure(TaieOcManageCode.FAIL.getCode(), "校验失败，对应机器许可过期，请联系管理员");
        }
    }


    //    解析到期时间
    public Date dateTime(String timeLicense) {
        SimpleDateFormat sdf = new SimpleDateFormat(TaieOcConstants.DATE_LONG_FORMAT);
        SM2Utils sm = new SM2Utils();
        //  1.解密签名内容：｛解密签名内容｝＝｛加密签名内容｝＋｛SM４解密｝＝｛签名内容｝＋｛时间戳｝
        String sign_content_decrypt = sm.decryptEcb("93f2eca686469186", timeLicense);
        //  2.验证签名：｛验证签名｝＝｛签名内容｝＋｛时间戳｝＋｛签名值｝＋｛SM２公钥｝
        //  3.分割截取SM2加密签名值及加密时间
        String sign_value_decrypt = sign_content_decrypt.split("==")[0];
        String datetime = sign_content_decrypt.split("==")[1];
        //使用SM2公钥验签
        Date date = null;
        try {
            date = sdf.parse(datetime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }


    @Override
    public DubboResult<Boolean> checkRobotLicenseTimeDubbo(String robotKey) {
        Boolean flag = Boolean.FALSE;
        if (StringUtils.isNotEmpty(robotKey)) {
            MachineLicenseInfoReq req = new MachineLicenseInfoReq();
            req.setRobotMachineKey(robotKey);
            MachineLicenseInfo respDto = machineLicenseMapper.selectMachineLicenseInfo(req);
            Boolean after = respDto.getEndTime().after(new Date());
            log.info("license许可到期时间校验结果：" + after);
            flag = after;
        }
        return DubboResult.newSuccess("成功", flag);
    }

}
