/**
 * 
 */
package org.springblade.core.license;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

import org.springblade.core.boot.properties.SpringBootProperties;
import org.springblade.core.license.model.LicenseCheckModel;
import org.springblade.core.license.model.LicenseContentModel;
import org.springblade.core.license.properties.LicenseProperties;
import org.springblade.core.license.system.LinuxServerInfo;
import org.springblade.core.license.system.MacServerInfo;
import org.springblade.core.license.system.WindowServerInfo;
import org.springblade.core.tool.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson2.JSON;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import lombok.extern.slf4j.Slf4j;

/**
 * @author wookvn
 * 
 * 校验License真假
 */
@Slf4j
@Component
public class LicenseManager {
	
	@Autowired
	private LicenseProperties licenseProperties;
	
	@Autowired
	private SpringBootProperties springBootProperties;
	
	//license过期时间戳
	private volatile LicenseContentModel licenseContent = null;
	
	/**
	 * 登录时，校验License
	 * @return
	 */
	public boolean validateOfLogin() {
		//开发环境不校验
		if("dev".equalsIgnoreCase(springBootProperties.getEnv()) || !licenseProperties.isEnabled()){
			return true;
		}
		long startTime = System.currentTimeMillis();
		log.info("#########【开始校验Lincese】#########");
		//licenseContent == null 表示首次，需要校验CPU序列号和主板序列号
		if(licenseContent == null) {
			if(StrUtil.isBlank(licenseProperties.getFilePath())) {
				throw new ServiceException("License授权文件没有配置");
			}
			File licenseFile = new File(licenseProperties.getFilePath());
			if(!licenseFile.exists()) {
				throw new ServiceException("未找到License授权文件");
			}
			List<String> readLines = FileUtil.readLines(licenseFile, StandardCharsets.UTF_8);
			if(CollectionUtil.isEmpty(readLines)) {
				throw new ServiceException("无效的License授权文件");
			}
			//获取加密后的数据
			String cipherText = readLines.get(0);
			log.info("License|cipherText={}", cipherText);
			try {
				//公钥解密
				String decrypt = SecureUtil.rsa(null, licenseProperties.getPublicKey()).decryptStr(cipherText, KeyType.PublicKey);
				licenseContent = JSON.parseObject(decrypt, LicenseContentModel.class);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				throw new ServiceException("错误的License授权文件.");
			}
			//开始校验: 获取服务器信息
			LicenseCheckModel licenseCheckModel = null;
			try {
				licenseCheckModel = getServerInfo();
				log.debug("服务器的校验信息:{}", JSON.toJSONString(licenseCheckModel));
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				throw new ServiceException("获取服务器信息出错，请联系管理员.");
			}
			//校验1:主板序列号是否正确
			if(!check(Arrays.asList(licenseContent.getMainBoardSerial()), licenseCheckModel.getMainBoardSerial())) {
				throw new ServiceException("当前服务器的主板序列号没在授权范围内.");
			}
			log.info("License|校验主板序列号通过.");
			//校验2:CPU序列号是否正确
			if(!check(Arrays.asList(licenseContent.getCpuSerial()), licenseCheckModel.getCpuSerial())) {
				throw new ServiceException("当前服务器的CPU序列号没在授权范围内.");
			}
			log.info("License|校验CPU序列号通过.");
		}
		//校验0:是否在正确的有效期内
		if(System.currentTimeMillis() > licenseContent.getExpireTime()) {
			throw new ServiceException("该License授权文件已过期.");
		}
		log.info("License|校验有效期通过.");
		//校验3:mac地址是否正确【不同docker容器IP和mac地址都是变化的；暂时不使用这2项做比对】
//		if(!check(Arrays.asList(licenseContent.getMacAddress()), licenseCheckModel.getMacAddresses())) {
//			throw new ServiceException("当前服务器的MAC地址没在授权范围内.");
//		}
//		log.info("License|校验MAC地址通过.");
		//校验4:IP地址是否正确 
//		if(!check(Arrays.asList(licenseContent.getIpAddress()), licenseCheckModel.getIpAddresses())) {
//			throw new ServiceException("当前服务器的IP没在授权范围内");
//		}
//		log.info("License|校验IP地址通过");
		log.info("#########【结束校验Lincese|cost:{}s】#########", (System.currentTimeMillis()-startTime)/1000.f);
		return true;
	}
	
	/**
	 * 	获取需要校验的服务器信息
	 * @return
	 * @throws Exception 
	 */
	private LicenseCheckModel getServerInfo() throws Exception {
		String osName = System.getProperty("os.name").toLowerCase();
		IServerInfo serverInfo = null;
		//根据不同的操作系统类型选择不同的数据获取方式
		if(osName.startsWith("windows")) {
			serverInfo = new WindowServerInfo();
		}else if(osName.startsWith("mac")) {
			serverInfo = new MacServerInfo();
		}else { //默认是linux
			serverInfo = new LinuxServerInfo();
		}
		return serverInfo.getServerInfo();
	}
	
	/**
	 * 屏蔽大小写和trim后做比较
	 * 校验expectedList的值只要存在于serverList中即可成功
	 * @param expectedList
	 * @param serverList
	 * @return
	 */
	private boolean check(List<String> expectedList, List<String> serverList) {
		if(CollectionUtil.isNotEmpty(expectedList) && CollectionUtil.isNotEmpty(serverList)) {
			String[] expectedArr = expectedList.stream().map(item -> item.trim().toLowerCase()).toArray(String[]::new);
			return serverList.stream().map(item -> item.trim().toLowerCase()).anyMatch(o -> StrUtil.containsAny(o, expectedArr));
		}
		return false;
	}
	
	/**
	 * 屏蔽大小写和trim后做比较
	 * @param expectedList
	 * @param server
	 * @return
	 */
	private boolean check(List<String> expectedList, String server) {
		if(CollectionUtil.isNotEmpty(expectedList) && StrUtil.isNotBlank(server)) {
			return expectedList.stream().map(String::trim).anyMatch(o -> o.equalsIgnoreCase(server.trim()));
		}
		return false;
	}
	
//	public static void main(String[] args) throws Exception {
//		String pkey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIgkJHvuorPcO9AG16EEVmgtO3um5FIKEJeb0ahQuakVvvtzE8pnyKTajXvRuZw+yWp/03P2FMMaAtTay+zvLPEDK6ERO6fBE1R2Ij5O36W4sHAB7YEA1itankCqvzAjWEK7kGkpHQiCPAdX/srKProktAmgW+7vqVwGhNJVbx7vAgMBAAECgYBjHoVdofHdp7P4knK97a2HbZ9IOMs1G9TWvQDZXeS+wXFqG2/GRuejdufZxWkw49m7a1Olsv2MysxS8vXUDJMX0tMc+GoHMLEhl/z6Qmx218sh1kOuBFIJQLl6qq5oUMMDPPpE07qOUSZ2Oeo+g04RlT1iuYi1rBp+uUU+0QpBcQJBAOzjlCnwHEGgNAfomqv6GGSXmq8/0F8ZWhT35qZiAgwD0ji9FVn720P1xdWaFcjTLB/Zt0ZM48jK3ot31yoPWXkCQQCTH9bjqbIEG49VcLYnoKle944U9F6U+pbUkbRL1VE/kSbn84OiaJ/s/jXKLVYEbUhvqGYXO6YNHCR5MyuKWomnAkAYIJnPp7AJExsZjxxp1cA0Rqivns1HUlq1dgZc/fB9bsozkzaggqFzi43J0rbTTIba+57KHzy4D8mY5OzaUNPpAkB2WD02AnGkpjqk4rZTqAO11XIf3vYZ5nzfXpjmCyCA/pSKLjKruHc0XsQL7m3rv7BtyMreU2fd0c5xA705XFyvAkEAlpPNkdsA8Tf+buYQ5iRoS9CuDJ6WjkcO/aFBX7yMcg8WqjA/vyqrZVzRsOfro80qjkaH3DpzaYV1YTv3h5N/ZQ==";
//		LicenseContentModel licenseContentModel = new LicenseContentModel();
//		licenseContentModel.setExpireTime(DateUtil.offset(new Date(), DateField.YEAR, 10).getTime());
//		licenseContentModel.setCpuSerial("D7 06 02 00 FF FB EB BF");
//		licenseContentModel.setMainBoardSerial("H6F6ML1");
//		licenseContentModel.setIpAddress("172.18.0.2");
//		licenseContentModel.setMacAddress("02-42-AC-12-00-02");
//		String data = JSON.toJSONString(licenseContentModel);
//		System.out.println(data);
//		System.out.println(SecureUtil.rsa(pkey, null).encryptBase64(data, KeyType.PrivateKey));
//	}
}