package org.wfc.common.license.runner;

import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.wfc.common.license.LicenseVerify;
import org.wfc.common.license.domain.LicenseVerifyParam;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@Data
public class LicenseCheckRunner implements ApplicationRunner {

    @Autowired
    private LicenseProperties licenseProperties;

    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private ScheduledFuture<?> scheduledFuture;


    // 启动定时任务
    public void startTimer() {
        scheduledFuture = scheduler.scheduleAtFixedRate(this::timer, 0, 30, TimeUnit.SECONDS);
    }

    // 停止定时任务
    public void stopTimer() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
        }
    }

    /**
     * 文件唯一身份标识 == 相当于人类的指纹一样
     */
    private static String md5 = "";
    private static boolean isLoad = true;

    public static void LicenseVerifyInstall(LicenseProperties licenseVerifyProperties) {
        new LicenseCheckRunner(licenseVerifyProperties);
    }

    public LicenseCheckRunner(LicenseProperties licenseProperties) {
        // startTimer();
        this.licenseProperties = licenseProperties;
        if (StrUtil.isNotEmpty(licenseProperties.getLicensePath())) {
            install();
            try {
                String readMd5 = getMd5(licenseProperties.getLicensePath());
                isLoad = true;
                if (LicenseCheckRunner.md5 == null || "".equals(LicenseCheckRunner.md5)) {
                    LicenseCheckRunner.md5 = readMd5;
                }
            } catch (Exception e) {

            }
        }
    }


    /**
     * 5秒检测一次，不能太快也不能太慢
     */
    protected void timer() {
        if (!isLoad) {
            return;
        }
        String readMd5 = null;
        try {
            readMd5 = getMd5(licenseProperties.getLicensePath());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 不相等，说明lic变化了
        if (!readMd5.equals(LicenseCheckRunner.md5)) {
            log.info("定时任务：检测到证书有变化");
            install();
            LicenseCheckRunner.md5 = readMd5;
        }

    }

    private void install() {
        log.info("++++++++ 开始安装证书 ++++++++");
        LicenseVerifyParam param = new LicenseVerifyParam();
        param.setSubject(licenseProperties.getSubject());
        param.setPublicAlias(licenseProperties.getPublicAlias());
        param.setStorePass(licenseProperties.getStorePass());
        // 相对路径resources资源目录
        String resourcePath = getClass().getClassLoader().getResource("").getPath();
        // 证书地址
//        param.setLicensePath(resourcePath + "license.lic");
        param.setLicensePath(licenseProperties.getLicensePath());
        // 公钥地址
//        param.setPublicKeysStorePath(resourcePath + "publicCerts.keystore");
        param.setPublicKeysStorePath(licenseProperties.getPublicKeysStorePath());
        // 安装证书
        LicenseVerify licenseVerify = new LicenseVerify();
        licenseVerify.install(param);
        log.info("++++++++ 证书安装结束 ++++++++");
    }

    /**
     * <p>获取文件的md5</p>
     */
    public String getMd5(String filePath) throws Exception {
        File file;
        String md5 = "";
        try {
            file = new File(filePath);
            if (file.exists()) {
                FileInputStream is = new FileInputStream(file);
                byte[] data = new byte[is.available()];
                is.read(data);
                md5 = calculateMD5(data);
                is.close();
            }
        } catch (FileNotFoundException e) {
            log.error("找不到证书文件 {}", e.getMessage());
        }
        return md5;
    }

    public static String calculateMD5(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(data);

            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("证书文件计算MD5失败 {}", e.getMessage());
            return null;
        }
    }


    @Override
    public void run(ApplicationArguments args) throws Exception {
        install();
        startTimer();
    }
}