package com.dxhy.common.auth;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.collection.ListUtil;
import com.dxhy.common.exception.auth.BadRequestException;
import com.dxhy.tools.Util.LicUtil;
import com.dxhy.tools.util.MachineUtil;
import org.apache.commons.io.FileUtils;
import org.junit.platform.commons.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @Author: chengyafu
 * @Date: 2022-03-31 16:26
 * @Description:
 */
@Component("authCheck")
@RefreshScope
public class AuthCheck implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(AuthCheck.class);
    @Value("${auth.licPath:}")
    private String DECODE_CLIENT_URL;

    Cache<String,byte[]> cache = CacheUtil.newTimedCache(60*1000);
    private static final String SUCCESS_LIC = "LIC";

    public Result auth() {
        Result r = new Result();
        r.setCode("1");
        r.setMsg("产品未授权，请联系管理员申请授权。");
        byte[] fileByte = null;
        try {
            fileByte = readFile();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return Result.error("4031", e.getMessage());
        }

        String lic;
        try {
            String cacheValue = (String) AuthCache.getAuthCache(AuthCache.MAC_DATE_CHECK);
            if (StringUtils.isBlank(cacheValue)) {
                lic = LicUtil.verificationLic(fileByte);
                cacheValue = StringUtils.isBlank(lic) ? SUCCESS_LIC : lic;//校验返回为空为成功
                AuthCache.putAuthCache(AuthCache.MAC_DATE_CHECK, cacheValue);
            } else {
                lic = SUCCESS_LIC.equals(cacheValue) ? null : cacheValue;
            }
        } catch (Exception e) {
            logger.error("授权校验失败，授权校验发生异常", e);
            return r;
        }

        if (StringUtils.isBlank(lic)) {
            r.setCode("0");
            r.setMsg("授权通过");
            return r;
        }
        logger.error("线程ID:{},授权未通过{}", Thread.currentThread().getId(), lic);
        if (lic.length() == 8) {
            r.setMsg(String.format("授权已到期，当前授权截止时间：%s，若需继续使用本产品，请联系管理员申请授权。", convertDate(lic)));
        }
        return r;
    }


    /**
     * 按照接口授权
     *
     * @param interfaceCode
     * @return
     */
    public boolean checkInterface(String interfaceCode) {
        try {
            Boolean cache = (Boolean) AuthCache.getAuthCache(AuthCache.INTERFACE_CHECK);
            if (null == cache) {
                cache = LicUtil.checkInterfaceCode(readFile(), interfaceCode);
                AuthCache.putAuthCache(AuthCache.INTERFACE_CHECK, cache);
            }
            return cache;
        } catch (Exception e) {
            logger.error("接口授权校验异常", e);
            throw new BadRequestException("接口授权校验异常");
        }
    }

    /**
     * 获取最大授权数量
     *
     * @return
     */
    private int getClientCount() {
        try {
            Integer cache = (Integer) AuthCache.getAuthCache(AuthCache.CLIENT_COUNT);
            if (null == cache) {
                cache = LicUtil.getClientCount(readFile());
                AuthCache.putAuthCache(AuthCache.CLIENT_COUNT, cache);
            }
            return cache;
        } catch (Exception e) {
            logger.error("授权数量校验异常", e);
            throw new BadRequestException("获取授权数量读取授权文件异常");
        }
    }

    /**
     * 判断是否能添加税号权限
     *
     * @return
     */
    public Result addClientAble() {
        int clientCount = getClientCount();
        List<String> authNsrsbhList = AuthCache.getAuthNsrsbhList();
        int leftCount = clientCount - authNsrsbhList.size();
        if (leftCount <= 0) {
//            return Result.error("1002", "当前用户数量已达到最大系统授权数量" + clientCount);
            Map<String, String> authInfo = getAuthInfo();
            String sqlx = authInfo.get(LicUtil.SQLX);
            String desc = "TEST".equals(sqlx) ? "测试" :"正式";
            return Result.error("1002", String.format("超过产品授权允许的最大使用单位数量，当前产品是%s授权，最大允许添加%s个使用单位（含直连单位）", desc, clientCount));

        }
        return Result.ok();
    }

    /**
     * 校验税号是否授权
     *
     * @param nsrsbh
     * @return
     */
    public Result checkNsrsbh(String nsrsbh) {
        List<String> authNsrsbhList = AuthCache.getAuthNsrsbhList();
        if (authNsrsbhList.isEmpty()) {
            return Result.error("4030","请先进行初始化配置再进行操作");
        }

        if(!authNsrsbhList.contains(nsrsbh)){
            return Result.error("4030","请先进行初始化配置再进行操作");
        }

        int count = getClientCount();
        if (authNsrsbhList.size() > count) {
            authNsrsbhList = ListUtil.sub(authNsrsbhList, 0, count);
        }
        if(!authNsrsbhList.contains(nsrsbh)){
            return Result.error("4031", "当前授权使用单位己用尽");
        }

        return Result.ok();
    }

    private byte[] readFile() throws Exception {
        byte[] fileByte = cache.get("licByte",false);
        if (null == fileByte) {
            if (StringUtils.isBlank(DECODE_CLIENT_URL)) {
                DECODE_CLIENT_URL = getDefaultLicFile();
            }

            File file = new File(DECODE_CLIENT_URL);
            if (!file.exists()) {
                logger.error("授权校验失败，授权文件不存在");
                throw new Exception("授权校验失败，授权文件不存在");
            }
            if (file.isDirectory()) {
                File[] files = file.listFiles(f -> f.getName().toLowerCase().endsWith("invoice.lic"));
                if (files != null && files.length > 0) {
                    String licPath = DECODE_CLIENT_URL + File.separator + files[0].getName();
                    file = new File(licPath);
                } else {
                    logger.error("授权校验失败，授权文件不存在");
                    throw new Exception("授权校验失败，授权文件不存在");
                }
            }

            try {
                byte[] bytes = FileUtils.readFileToByteArray(file);
                if (null == bytes) {
                    logger.error("授权校验失败，授权文件内容为空");
                    throw new Exception("授权校验失败，授权文件内容为空");
                }
                cache.put("licByte",bytes);
                fileByte = bytes;
            } catch (IOException e) {
                logger.error("授权校验失败，读取授权文件异常");
                throw e;
            }
        }
        return fileByte;
    }

    private String convertDate(String date) {
        return new StringBuilder(date).insert(6, "-").insert(4, "-").toString();
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
//        readFile();
    }

    private String getDefaultLicFile() {
        File classFilePath = new File(Thread.currentThread().getContextClassLoader().getResource("").getPath());
        String jarFolderPath;//jar包所在文件夹路径
        String property = System.getProperty("os.name");
        if (property.toLowerCase().contains("window")) {
            jarFolderPath = classFilePath.getParent();
        } else {
            //file:/home/dxhy/application/einvoice-mangement-9098/einvoice-mangement.jar!/BOOT-INF/class
            File parentFile = classFilePath.getParentFile().getParentFile().getParentFile();
            jarFolderPath = parentFile.getPath().replace("file:", "");
        }
        logger.info("jar路径：" + jarFolderPath);
        return jarFolderPath;

    }

    public Map<String, String> getAuthInfo()  {
        byte[] data = null;
        try {
            data = readFile();
        } catch (Exception e) {
            logger.error("读取授权文件异常", e);
            throw new BadRequestException("4031", e.getMessage());
        }
        Map<String, String> map = LicUtil.getLicInfo(data);
        String code = map.get(LicUtil.CODE);
        if (!"0".equals(code)) {
            throw new BadRequestException(code, map.get(LicUtil.MSG));
        }
        return map;
    }

    public static void main(String[] args) {
        String macAddress = MachineUtil.getMacAddress();
        System.out.println(macAddress);
    }

}
