package com.qmth.boot.core.solar.crypto;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qmth.boot.core.solar.model.AppLicense;
import com.qmth.boot.tools.codec.CodecUtils;
import com.qmth.boot.tools.crypto.AES;
import com.qmth.boot.tools.crypto.RSA;
import com.qmth.boot.tools.device.DeviceInfo;
import com.qmth.boot.tools.models.ByteArray;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Arrays;

/**
 * 应用许可证解析工具
 */
public class AppLicenseUtil {

    private static final Logger log = LoggerFactory.getLogger(AppLicenseUtil.class);

    private static final String PUBLIC_KEY_PATH = "license/public.key";

    /**
     * 构造当前设备加密信息文件
     *
     * @return
     */
    public static ByteArray buildDeviceInfo() throws Exception {
        return RSA.getPublicKey(ByteArray.fromResource(PUBLIC_KEY_PATH).value())
                .encrypt(new ObjectMapper().writeValueAsBytes(DeviceInfo.current()));
    }

    /**
     * 通过许可证文件路径尝试解析
     *
     * @param filePath
     * @return
     */
    public static AppLicense parseLicense(String filePath, String version) {
        try {
            return parseLicense(ByteArray.fromFile(new File(filePath)).value(), version);
        } catch (Exception e) {
            log.error("Solar license parse error", e);
        }
        return null;
    }

    /**
     * 解析授权文件获得授权信息
     *
     * @param data    授权文件二进制内容
     * @param version 版本号格式为x.x.x
     * @return
     */
    public static AppLicense parseLicense(byte[] data, String version) {
        try {
            byte[] original = ArrayUtils.subarray(data, 1, data.length);
            // 不限制设备
            if (data[0] == 0) {
                // 不绑定硬件
            }
            //限制设备，不限制版本
            else if (data[0] == 1) {
                // 获取当前设备标识
                String deviceId = DeviceInfo.current().uuid();
                // 使用设备标识进行AES解密
                original = AES.decrypt(original, deviceId.substring(0, 16), deviceId.substring(16)).value();
            }
            //不限制设备，限制版本
            else if (data[0] == 2) {
                // 获取当前版本号MD5
                String versionMd5 = ByteArray.md5(version).toHexString();
                // 使用版本号MD5进行AES解密
                original = AES.decrypt(original, versionMd5.substring(0, 16), versionMd5.substring(16)).value();
            }
            //限制设备，限制版本
            else if (data[0] == 3) {
                // 获取当前设备标识
                String deviceId = DeviceInfo.current().uuid();
                // 获取当前版本号MD5
                String versionMd5 = ByteArray.md5(version).toHexString();
                // 使用版本号MD5与设备标识进行两次AES解密
                original = AES
                        .decrypt(AES.decrypt(original, versionMd5.substring(0, 16), versionMd5.substring(16)).value(),
                                deviceId.substring(0, 16), deviceId.substring(16)).value();
            } else {
                return null;
            }
            //截取前16位摘要信息
            byte[] digest = ArrayUtils.subarray(original, 0, 16);
            //进行RSA解密
            byte[] content = RSA.getPublicKey(ByteArray.fromResource(PUBLIC_KEY_PATH).value())
                    .decrypt(ArrayUtils.subarray(original, 16, original.length)).value();
            //比对摘要是否一致
            if (Arrays.equals(digest, CodecUtils.md5(content))) {
                return new ObjectMapper().readValue(content, AppLicense.class);
            }
        } catch (Exception e) {
            log.error("Solar license parse error", e);
        }
        return null;
    }

}
