package com.qmth.paper.library.common.contant;

import cn.hutool.core.date.DateUtil;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qmth.boot.core.uid.service.UidService;
import com.qmth.paper.library.common.annotation.DBVerify;
import com.qmth.paper.library.common.bean.result.DBVerifyResult;
import com.qmth.paper.library.common.entity.BasicSchool;
import com.qmth.paper.library.common.entity.SysUser;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.service.BasicSchoolService;
import com.qmth.paper.library.common.util.Base64Util;
import com.qmth.paper.library.common.util.ServletUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.cglib.beans.BeanMap;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.*;

/**
 * @Description: 系统常量
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2019/10/11
 */
public class SystemConstant {
    /**
     * 系统常量
     */
    public static final int OCR_CONNECTION_TIMEOUT_IN_MILLIS = 2000;
    public static final int OCR_SOCKET_TIMEOUT_IN_MILLIS = 60000;
    public static final String CHARSET_NAME = "UTF-8";
    public static final String CHARSET_GBK = "gbk";
    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
    public static final String MD5 = "MD5";
    public static final String SUCCESS = "success";
    public static final String EXTEND_COLUMN = "extendColumn";
    public static final String IMAGE_TEMP = "image-temp";
    public static final String TEMP = "temp";
    public static final String SESSION = "session:";
    public static final String TASK = "task";
    public static final String TB_TASK_ID = "tbTaskId";
    public static final String USER = "account";
    public static final String USER_ID = "userId";
    public static final String SCHOOL_ID = "schoolId";
    public static final String SCHOOL = "school";
    public static final String ORG = "org";
    public static final String ERROR = "/error";
    public static final String DEFAULT_PASSWORD = "MTIzNDU2";
    public static final String UPDATE_TIME = "updateTime";
    public static final String OCR_WORDS_RESULT = "words_result";
    public static final String OCR_ERROR_MSG = "error_msg";
    public static final String OCR_WORDS = "words";
    public static final String PATH = "path";
    public static final String PDF_PATH = "pdfPath";
    public static final String TYPE = "type";
    public static final String LOCAL = "local";
    public static final String OSS = "oss";
    public static final String LOGO = "logo";
    public static final String UPLOAD_TYPE = "uploadType";
    public static final String ID = "id";
    public static final String FILE = "file";
    public static final String SIZE = "size";
    public static final String EXCEL_PREFIX = ".xlsx";
    public static final String ZIP_SUFFIX = ".zip";
    public static final String PDF_SUFFIX = ".pdf";
    public static final String SCAN_TASK_CODE_PREFIX = "T";
    public static final String TMP_DIR = "java.io.tmpdir";

    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String SHORT_DATE_PATTERN = "yyyy-MM-dd";
    public static final int PAGE_SIZE_MIN = 10;
    public static final int PAGE_SIZE_MAX = 500;
    public static final int PAGE_NUMBER_MIN = 1;
    public static final int IN_SIZE_MAX = 1000;
    public static final String COMMA = ",";
    public static final String ORG_POINT = ".";
    public static final String HYPHEN = "-";
    public static final String ADMIN_CODE = "admin";
    public static final String AUTH = "auth";//命题老师id
    //    public static final int MAX_RETRY_CREATE_PDF_COUNT = 5;
    //英文字母、数字、中文括号、英文括号、下划线(_)、减号(-)、中文横线(—)
    public static final String SYS_USER = "sysUser";
    public static final List<Long> MENU_MANAGE = Arrays.asList(507L, 508L, 530L, 531L, 675L, 676L);
    public static final String ORG_SPLIT = "/";
    public static final String EXCEL_PROTECT_KEY = "Qmth87863577";
    public static final String ZIP_ENCRYPT_PWD = "qmthzip";
    //英文字母、数字、中文括号、英文括号、下划线(_)、减号(-)、中文横线(—)
    public static final String REGULAR_EXPRESSION_OF_CODE = "[a-zA-Z0-9](\\w+)?-?(\\w+)?—?(\\w+)?(\\((\\w+)?-?(\\w+)?—?(\\w+)?\\))?(\\（(\\w+)?-?(\\w+)?—?(\\w+)?\\）)?(\\w+)?";
    public static final String REGULAR_EXPRESSION_OF_PHONE = "((\\d{3,4})|(\\(\\d{3,4}\\)-))?\\d{7,8}";
    public static final String REGULAR_EXPRESSION_OF_CODE_PRIMARY_DIMENSION = "[A-Z]";
    public static final String REGULAR_EXPRESSION_OF_CODE_SECOND_DIMENSION = "[A-Z][1-9][0-9]*";
    public static final String REGULAR_EXPRESSION_OF_NUMBER = "^\\d{n}$";
    public static final String REGULAR_EXPRESSION_OF_NUMBER_LETTER = "^\\w+$";

    public static final String ERROR_DATA_LIST = "errorDataList";
    public static final String DATASOURCE = "datasource";
    public static final String DATA_COUNT = "dataCount";
    public static final String SUCCESS_DATA_COUNT = "successDataCount";
    public static final String ERROR_DATA_COUNT = "errorDataCount";
    public static final String HAS_ERROR_DATA = "hasErrorData";
    public static final String COLUMN_NAMES = "columnNames";


    public static final String DOUBLE_SLASH = "\\\\";
    public static final String SINGLE_SLASH = "/";

    /**
     * 缓存配置
     */
    public static final String CACHE_NAME = "paperLibraryCache";
    public static final String ROLE_CACHE_NAME = "roleCache";

    /**
     * 鉴权
     */
    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 SIGN = "sign";

    /**
     * redis
     */
    public static final int DEFAULT_SESSION_EXPIRE = 1;//过期时间1天
    public static final long REDIS_DEFAULT_EXPIRE_TIME = 24 * 60L * 60L;//过期时间24小时

    /**
     * aes相关
     */
    public static final String AES = "AES";
    public static final String AES_MODE_PKCS5 = "AES/CBC/PKCS5Padding";//用这个模式，规则必须为16位
    public static final String AES_MODE_PKCS7 = "AES/CBC/PKCS7Padding";//用这个模式，规则必须为16位
    public static final String AES_RULE = "1234567890123456";//aes密钥

    public static final String LOG_ERROR = "请求出错:{}";

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

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

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

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


    /**
     * 模糊查询时调用以去除符号"%","_"特殊字符对查询结果的影响
     *
     * @param param 要校验的参数
     * @return 转译后的参数
     */
    public static String translateSpecificSign(String param) {
        if (param == null) {
            return null;
        }
        if (param.contains("%")) {
            param = param.replaceAll("%", "\\\\%");
        }
        if (param.contains("_")) {
            param = param.replaceAll("_", "\\\\_");
        }
        return param;
    }

    public static boolean strNotNull(String str) {
        return str != null && !"".equals(str.trim()) && str.length() > 0 && !str.equals("null");
    }

    /**
     * Long 类型的参数不为空
     *
     * @param x 参数
     * @return true：不为空、false：为空
     */
    public static boolean longNotNull(Long x) {
        return x != null && x > 0;
    }

    public static Long getHeadOrUserSchoolId() {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        Long schoolId;
        if (Objects.nonNull(ServletUtil.getRequestHeaderSchoolIdByNotVaild())) {
            schoolId = Long.parseLong(ServletUtil.getRequestHeaderSchoolIdByNotVaild().toString());
        } else {
            schoolId = sysUser.getSchoolId();
        }
        return schoolId;
    }

    /**
     * 检验字段
     *
     * @param obj   被检验的映射类对象
     * @param clazz 该对象的类
     * @return 检验结果(状态 、 信息)
     * @throws IllegalAccessException 异常
     */
    public static DBVerifyResult 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);
            if (Objects.isNull(dbVerify)) {
                continue;
            }
            String value = dbVerify.value();
            boolean required = dbVerify.required();
            int min = dbVerify.min();
            int max = dbVerify.max();

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

    /**
     * 验证参数任意一个为空
     *
     * @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;
    }

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

    /**
     * 图片转换
     *
     * @param imgBase64
     * @param filePath
     * @throws IOException
     */
    public static void base64ToImage(String imgBase64, String filePath) throws IOException {
        OutputStream out = null;
        try {
            byte[] b = Base64Util.decode(imgBase64);
            out = new FileOutputStream(filePath);
            IOUtils.write(b, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(out)) {
                out.flush();
                out.close();
            }
        }
    }

    /**
     * 将对象装换为map
     *
     * @param bean
     * @return
     */
    public static Map<String, Object> beanToMap(Object bean) {
        Map map = new HashMap<>();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(String.valueOf(key), beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将map装换为javabean对象
     *
     * @param map
     * @param bean
     * @return
     */
    public static Object mapToBean(Map<String, Object> map, Object bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 获取本地文件host
     *
     * @param hostUrl
     * @return
     */
    public static String getLocalFileHost(String hostUrl) {
        BasicSchoolService basicSchoolService = SpringContextHolder.getBean(BasicSchoolService.class);
        if (hostUrl.contains("*")) {
            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
            BasicSchool basicSchool = basicSchoolService.getById(sysUser.getSchoolId());
            hostUrl = hostUrl.replace("*", basicSchool.getCode());
        }
        return hostUrl;
    }

    /**
     * 获取本地文件路径
     *
     * @param filePath
     * @return
     */
    public static String getLocalFilePath(String hostUrl, String filePath) {
        Optional.ofNullable(hostUrl).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置文件访问地址"));
        String[] hostArray = hostUrl.split(":");
        if (hostArray.length == 2 && filePath.contains(SystemConstant.IMAGE_TEMP)) {
            filePath = filePath.substring(filePath.indexOf(SystemConstant.IMAGE_TEMP));
        }
        return filePath;
    }

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

    /**
     * 获取临时文件
     *
     * @param suffix
     * @return
     */
    public static File getFileTempDirVar(String suffix) {
        File fileTmpDir = new File(System.getProperty(SystemConstant.TMP_DIR));
        if (!fileTmpDir.exists()) {
            fileTmpDir.mkdirs();
        }
        File file = new File(System.getProperty(SystemConstant.TMP_DIR), SystemConstant.getNanoId() + suffix);
        return file;
    }

    /**
     * 获取临时文件
     *
     * @param suffix
     * @return
     */
    public static File getFileTempVar(String suffix) throws IOException {
        File fileDir = new File(SystemConstant.TEMP);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        return new File(fileDir, SystemConstant.getNanoId() + suffix);
    }

   /* 以前的方式
   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.TMP_DIR, suffix);
        return file;
    }*/

    public static void addSummary(StringJoiner stringJoinerSummary, String message) {
        // 时间：事件
        stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), "->", message));
    }
}