package com.qmth.jkserver.constant;

import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qmth.boot.core.uid.service.UidService;
import com.qmth.jkserver.annotation.DBVerify;
import com.qmth.jkserver.common.Constants;
import com.qmth.jkserver.core.AesEncryptUtil;
import com.qmth.jkserver.core.cache.JkCacheService;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.enums.UserRole;
import com.qmth.jkserver.model.Attachment;
import com.qmth.jkserver.model.User;
import com.qmth.jkserver.params.VerifyResultParams;
import com.qmth.jkserver.util.FileStoreUtil;
import com.qmth.jkserver.util.ServletUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @Description: 系统constant
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/12/11
 */
public class SystemConstant {
    private final static Logger log = LoggerFactory.getLogger(SystemConstant.class);

    /**
     * 系统常量
     */
    public static final String PREFIX_URL_COMMON = "/system/common";
    public static final String PREFIX_URL_AUTH = "/system/auth";
    public static final String OS_NAME = "os.name";
    public static final String CHARSET_GBK = "gbk";
    public static final String WINDOWS = "Windows";
    public static final String CHARSET_NAME = "UTF-8";
    public static final String TASK = "task";
    public static final String YUN_EXAM_ID = "yunExamId";
    public static final String USER = "user";
    public static final String TYPE = "type";
    public static final String LOCAL = "local";
    public static final String OSS = "oss";
    public static final String PATH = "path";
    public static final String UPLOAD_TYPE = "uploadType";
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String VALUE_OF_BLANK_REQUIRED_FIELD = "#";
    public static final String JOINT_MARK = "_";
    public static final String HYPHEN = "-";
    public static final String TMP_DIR = "java.io.tmpdir";
    public static final BigDecimal RATE_BIG_DECIMAL = new BigDecimal(100);
    public static final String TEMP = "temp";
    public static final String ZIP_PREFIX = ".zip";
    public static final String JSON_PREFIX = ".json";
    public static final String WILL_DELETE_PATH = "willDeletePath";
    public static final String EXTEND_COLUMN = "extendColumn";
    public static final Integer SYNC_DATA_LIMIT = 500;
    public static final String LOG_ERROR = "请求出错:{}";
    public static final String BODY = "body";
    public static final String CREATE_TIME = "createTime";
    public static final String UPDATE_TIME = "updateTime";
    public static final String ORG_SPLIT = "/";
    public static final String THREAD_POOL_CORE_SIZE = "thread.pool.core.size";
    public static final String CUSTOM_THREAD_POOL_CORE_SIZE = "custom.thread.pool.core.size";
    //    public static final String JKSERVER_SINGLE = "jkserver.single";
    public static final String CLOUDMARK_HOST_URL = "cloudmark.host.url";
    public static final String SYS_CONFIG_KEY_CHARSETS = "sys.txt.charset";
    public final static String SCHOOL_ID = "schoolId";
    public final static String VERSION = "3.4.0.1";
    public static final int PAGE_NUMBER_MIN = 1;
    public static final int PAGE_SIZE_MIN = 10;
    public static final int PAGE_SIZE_MAX = 500;

    /**
     * wps
     */
    public static final String WPS_DOMAIN = "wps.domain";
    public static final String WPS_ACCESS_KEY = "wps.access.key";
    public static final String WPS_SECRET_KEY = "wps.secret.key";
    public static final String CONTENT_TYPE_JSON = "application/json";
    public static final String CONTENT_TYPE_FORM_DATA = "multipart/form-data";
    public static final String QUESTION_LIST = "/api/question/list";
    public static final String QUESTION_DETAIL = "/api/question/detail";
    public static final String QUESTION_CALCULATE_QUERY = "/api/question/calculate/query";
    public static final String QUESTION_CALCULATE_APPLY = "/api/question/calculate/upload/file/apply";
    public static final String WPS = "wps";
    public static final String WPS_DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
    public static final String WPS_QUESTION = "wps_question";

    /**
     * http设置
     */
    public static final int CONNECT_TIME_OUT = 1000 * 60 * 2;//请求超时
    public static final int SOCKET_CONNECT_TIME_OUT = 1000 * 60 * 30;//读取数据超时

    /**
     * 系统相关
     */
    public static final String METHOD = "post";
    public static final String API_OPEN = "/api/open";
    public static final String WPS_API_OPEN = "/api/wps";
    public static final String SYSTEM_EXAM_TASK = "/system/exam/task";

    /**
     * 云阅卷相关
     */
    public static final String ACCESS_KEY = "accessKey";
    public static final String ACCESS_SECRET = "accessSecret";
    public static final String CLOUD_MARK_EXAM_SAVE_API = "/api/exam/save";
    public static final String CLOUD_MARK_SUBJECT_SAVE_API = "/api/exam/subject/save";
    public static final String CLOUD_MARK_FILE_UPLOAD_API = "/api/file/{type}/upload";
    public static final String CLOUD_MARK_STUDENT_SAVE_API = "/api/exam/student/save";
    public static final String CLOUD_MARK_STUDENT_SCORE_API = "/api/exam/student/score";

    //    public static final String ACCESS_KEY = "c2465f31918e498b99f8d55d06b206fd";
//    public static final String ACCESS_SECRET = "cqqEQy3n5kDsOCCX9gTKTIcp";
    public static final String FILE_UPLOAD_VARIABLE_URL = "\\{type\\}";

    /**
     * 鉴权
     */
    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_TIME = "time";
//    public static final String HEADER_PLATFORM = "platform";
//    public static final String HEADER_DEVICE_ID = "deviceId";
//    public static final String TOKEN = "token";
    public static final String MD5 = "MD5";
    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);

    /**
     * 第三方系统
     */
    public static final String THIRD_ORG_NAME_HMJL = "禾木检录系统";
    public static final String THIRD_ORG_CODE_HMJL = "hmjl";
    public static final long THIRD_ORG_YEAR_HMJL = 10L;

    /**
     * 缓存配置
     */
    public static final String USER_ACCOUNT_CACHE = "user:account:cache";
    public static final String SCHOOL_CACHE = "school:cache";
    public static final String SCHOOL_CODE_CACHE = "school:code:cache";
    public static final String SYS_CONFIG_CACHE = "sys:config:cache";

    /**
     * 线程池配置
     */
    public static final String THREAD_POOL_NAME = "taskThreadPool";
    public static final int THREAD_POOL_KEEP_ALIVE_SECONDS = 10;
    public static final int THREAD_POOL_QUEUE_CAPACITY = 500;

//    /**
//     * 初始化附件文件路径
//     */
//    public static void initTempFiles() {
//        StringJoiner localPath = new StringJoiner("").add(System.getProperty(SystemConstant.USER_DIR));
//        String mkdir = localPath.toString().substring(0, localPath.toString().lastIndexOf(File.separator));
//        File workDir = new File(mkdir + File.separator + "work");
//        if (!workDir.exists()) {
//            workDir.mkdirs();
//        }
//        File storageDir = new File(mkdir + File.separator + "storage");
//        if (!storageDir.exists()) {
//            storageDir.mkdirs();
//        }
//        FileStoreConfig fileStoreConfig = BeanFactory.getBean(FileStoreConfig.class);
//        fileStoreConfig.setWorkRoot(workDir.getPath());
//        fileStoreConfig.setStorageRoot(storageDir.getPath());
//    }

    /**
     * id转换为long
     *
     * @return
     */
    public static Long convertIdToLong(String id) {
        return Objects.nonNull(id) && id.length() > 0 ? Long.parseLong(id) : null;
    }

    /**
     * 验证参数任意一个为空
     *
     * @param objects 要非空校验的参数
     */
    public static boolean isOneNull(Object... objects) {
        boolean result = false;
        for (Object object : objects) {
            if (Objects.isNull(object)) {
                result = true;
            } else if (object instanceof String) {
                String param = String.valueOf(object);
                if (param.length() == 0 || param.equals("null")) {
                    result = true;
                }
            } else if (object instanceof Long) {
                Long param = SystemConstant.convertIdToLong(String.valueOf(object));
                if (param == null || param == 0) {
                    result = true;
                }
            } else if (object instanceof Integer) {
                int param = Integer.parseInt(String.valueOf(object));
                if (param == 0) {
                    result = true;
                }
            }
        }
        return result;
    }

    /**
     * 检验数据库字段
     *
     * @param obj   被检验的映射类对象
     * @param clazz 该对象的类
     * @return 检验结果(状态 、 信息)
     * @throws IllegalAccessException 异常
     */
    public static VerifyResultParams verifyDBFields(Object obj, Class<?> clazz) throws IllegalAccessException {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true); // 解除封装
            String fieldValue = String.valueOf(field.get(obj));
            DBVerify dbVerify = field.getAnnotation(DBVerify.class);
            String value = dbVerify.value();
            boolean required = dbVerify.required();
            int length = dbVerify.length();

            if (required) {
                if (fieldValue == null || fieldValue.length() == 0 || fieldValue.equals("null")) {
                    return new VerifyResultParams(false, "[" + value + "]为必须字段，不能为空");
                }
            }
            if (fieldValue != null && length > 0) {
                if (fieldValue.length() > length) {
                    return new VerifyResultParams(false, "[" + value + "]超出最大长度限制，最大限制[" + length + "]");
                }
            }
        }
        return new VerifyResultParams(true, "成功");
    }

//    /**
//     * 获取全局uuid
//     *
//     * @return
//     */
//    public static String getUuid() {
//        return String.valueOf(UUID.randomUUID()).replaceAll("-", "");
//    }

    /**
     * 获取全局uuid
     *
     * @return
     */
    public static String getNanoId() {
        return NanoIdUtils.randomNanoId();
    }

    /**
     * distinct去重
     *
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 获取附件文件
     *
     * @param attachment
     * @return
     */
    public static File getAttachmentFile(Attachment attachment) throws Exception {
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        //2020-12-19日加入阿里云下载
        File storePath = null;
        File target = null;
        if (fileStoreConfig.storageIsOss()) {
            storePath = new File(fileStoreConfig.getStorageRoot());
            String path = storePath + File.separator + attachment.getAccessUri();
            path = path.replaceAll("\\\\", "/");
            target = fileStoreConfig.ossDownload(path, path, fileStoreConfig.getStorageRoot());
        } else {
            storePath = new File(fileStoreConfig.getStorageRoot());
            target = new File(storePath, attachment.getAccessUri().replaceAll("\\\\", "/"));
        }
        if (!target.exists() || !target.isFile()) {
            throw new JkServerException(JkServerException.SYSTEM_EXCEPTION.getCode(), "文件在服务器上不存在");
        }
        return target;
    }

    /**
     * 删除文件
     *
     * @param folder
     * @throws Exception
     */
    public static void deleteFolder(File folder) throws Exception {
        if (folder.exists()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        //递归直到目录下没有文件
                        deleteFolder(file);
                    } else {
                        //删除
                        file.delete();
                    }
                }
            }
            //删除
            folder.delete();
        }
    }

    /**
     * 获取数据库uuid
     *
     * @return
     */
    public static Long getDbUuid() {
        UidService uidservice = SpringContextHolder.getBean(UidService.class);
        return uidservice.getId();
    }

    /**
     * 获取临时文件
     *
     * @param suffix
     * @return
     */
    public static File getFileTempVar(String suffix) throws IOException {
        File fileTmpDir = new File(System.getProperty(SystemConstant.TMP_DIR));
        if (!fileTmpDir.exists()) {
            fileTmpDir.mkdirs();
        }
        File file = File.createTempFile(SystemConstant.TEMP, suffix);
        log.info("getFileTempVar_absolutePath:{}", file.getAbsolutePath());
        return file;
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String urlEncode(String part) {
        try {
            return URLEncoder.encode(part, SystemConstant.CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            throw new JkServerException(e.getMessage());
        }
    }

    /**
     * 只允许超管操作的接口
     */
    public static void superOper() {
        JkCacheService jkCacheService = SpringContextHolder.getBean(JkCacheService.class);
        String token = ServletUtil.getRequest().getHeader(Constants.REQUEST_HEADER_TOKEN);
        User user = SystemConstant.tokenGetUser(token);
        if (user == null) {
            throw new JkServerException("获取用户信息失败");
        }
        if (!user.getRole().equals(UserRole.SUPER_ADMIN)) {
            throw new JkServerException("只允许超级管理员操作");
        }
    }

    /**
     * token获取user信息
     *
     * @param token
     * @return
     */
    public static User tokenGetUser(String token) {
        String signature = AesEncryptUtil.decrypt(token);
        if (Objects.nonNull(signature) && !Objects.equals(signature.trim(), "")) {
            JkCacheService cacheService = SpringContextHolder.getBean(JkCacheService.class);
            String[] strs = signature.split("_");
            User user = (User) cacheService.getObj(Constants.CACHE_USER + strs[0]);
            return user;
        } else {
            return null;
        }
    }

    /**
     * 获取文件的层级数
     *
     * @param file
     * @param map
     * @return
     */
    public static Map<String, Object> getFileDirectoryCount(File file, Map<String, Object> map) {
        if (Objects.nonNull(file) && file.exists() && file.isDirectory()) {
            File[] f = file.listFiles();
            int fileDirectoryCount = 0;
            if (map.containsKey("fileDirectoryCount")) {
                fileDirectoryCount = (int) map.get("fileDirectoryCount");
            }
            fileDirectoryCount++;
            log.info("目录名：{},路径:{}", file.getName(), file.getAbsolutePath());
            map.put(fileDirectoryCount + "", file.getAbsolutePath());
            map.put("fileDirectoryCount", fileDirectoryCount);
            if (f.length > 0) {
                map = getFileDirectoryCount(f[0], map);//递归
            }
        }
        return map;
    }
}