package com.bocloud.ims.service.utils;

import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.topology.*;
import com.bocloud.ims.repository.topology.InstanceRepository;
import com.bocloud.ims.repository.topology.PropertyItemRepository;
import com.bocloud.ims.repository.topology.PropertyRepository;
import com.bocloud.ims.repository.topology.RegularExpressionRepository;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author lyy
 * @since 2018-02-01
 */
public class ValidateHelper {
    private static Logger logger = LoggerFactory.getLogger(ValidateHelper.class);
    private InstanceRepository instanceRepository;
    private PropertyRepository propertyRepository;
    private PropertyItemRepository propertyItemRepository;

    private RegularExpressionRepository regularExpressionRepository;

    public ValidateHelper(InstanceRepository instanceRepository, PropertyRepository propertyRepository, PropertyItemRepository propertyItemRepository, RegularExpressionRepository regularExpressionRepository) {
        this.instanceRepository = instanceRepository;
        this.propertyRepository = propertyRepository;
        this.propertyItemRepository = propertyItemRepository;
        this.regularExpressionRepository = regularExpressionRepository;
    }

    /**
     * 数据校验
     *
     * @param instance
     * @return
     */
    public String validateInstance(Instance instance) {
        StringBuilder message = new StringBuilder();
        List<Property> propertiesAll = new ArrayList<>();
        try {
            propertiesAll = propertyRepository.queryByModuleId(instance.getModuleId());
        } catch (Exception e) {
            logger.error("查询失败", e);
            message.append("加载属性失败;");
        }
        // 查出所有属性
        Map<Long, Property> propertiesAllMap = Maps.newHashMap();
        for (Property property : propertiesAll) {
            if (property.isCheckBox() || property.isRedio() || property.isSelect() || property.isTable()) {
                try {
                    property.setItem(propertyItemRepository.queryByPropertyId(property.getId()));
                } catch (Exception e) {
                    logger.error("查询错误");
                }
            }
            propertiesAllMap.put(property.getId(), property);
        }
        List<InstanceValue> properties = instance.getProperties();
        Iterator<InstanceValue> iterator = properties.iterator();
        while (iterator.hasNext()) {
            InstanceValue instanceValue = iterator.next();
            instanceValue.setInstanceId(instance.getId());
            Property property = propertiesAllMap.get(instanceValue.getPropertyId());
            if (property == null) {
                iterator.remove();
                continue;
            }
            instanceValue.setProperty(property);
            // 是否补充默认值
            if (StringUtils.isEmpty(instanceValue.getPropertyValue())
                    && StringUtils.isNotEmpty(property.getDefaultValue())) {
                instanceValue.setPropertyValue(property.getDefaultValue());
            }
            // 下拉框校验
            if ((property.isSelect() || property.isRedio())
                    && StringUtils.isNotEmpty(instanceValue.getPropertyValue())) {
                validateSelect(instance, message, instanceValue, property);
            } else if (property.isCheckBox() && StringUtils.isNotEmpty(instanceValue.getPropertyValue())) {
                validateCheckBox(instance, message, instanceValue, property);
            } else if (property.isFloat() || property.isInteger()) {
                validateNumber(message, instanceValue, property);
            } else if (property.isTable()) {
                /**
                 * 校验空白行
                 */
                validateTable(message, instanceValue, property);
            } else if (property.isQuote() && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
                validateQuote(message, instanceValue, property);
            } else if ((property.isTextarea() || property.isTextfield()) && null != property.getRegexpId()
                    && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
                // 正则校验
                validateTextarea(message, instanceValue, property);
            } else if (property.isDate() && StringUtils.isNotEmpty(instanceValue.getPropertyValue())) {
                validateDate(message, instanceValue, property);
            } else if (property.isTime() && StringUtils.isNotEmpty(instanceValue.getPropertyValue())) {
                validateTime(message, instanceValue, property);
            }

            // 必填校验
            if (!property.isTable() && property.getRequired()
                    && StringUtils.isEmpty(instanceValue.getPropertyValue())) {
                message.append("属性[" + property.getName() + "]不能为空;");
            }
            // 长度校验
            if (!property.isTable() && null != property.getLength() && property.getLength() > 0
                    && !StringUtils.isEmpty(instanceValue.getPropertyValue())
                    && instanceValue.getPropertyValue().length() > property.getLength()) {
                message.append("属性[" + property.getName() + "]超出最大长度[" + property.getLength() + "];");
            }
            // 唯一的字段记录
            if (property.getUniqued() && !StringUtils.isEmpty(instanceValue.getPropertyValue())
                    && message.length() == 0) {
                validateUnique(instance, message, instanceValue, property);

            }
            propertiesAllMap.remove(instanceValue.getPropertyId());
        }
        // 是否缺少属性
        if (!propertiesAllMap.isEmpty()) {
            for (Property property : propertiesAllMap.values()) {
                if (property.getRequired()) {
                    message.append("[" + property.getName() + "]为必填属性，不可缺少;");
                }
            }

        }
        return message.toString();
    }

    private void validateUnique(Instance instance, StringBuilder message, InstanceValue instanceValue,
                                Property property) {
        // 名称唯一 其他字段组合唯一
        if ("bname".equals(property.getCode())) {
            message.append(
                    uniqueValidateByBname(instance.getModuleId(), instanceValue.getPropertyValue(), instance.getId()));
        } else {
            message.append(uniqueValidateByProperty(instance.getModuleId(), instance.getId(), property.getCode(),
                    property.getName(), instanceValue.getPropertyValue()));
        }
    }

    private void validateTime(StringBuilder message, InstanceValue instanceValue, Property property) {
        // 时间格式校验
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dstr = instanceValue.getPropertyValue();
        try {
            sdf.parse(dstr);
        } catch (ParseException e) {
            message.append("[" + property.getName() + "]不符合时间格式[yyyy-MM-dd HH:mm:ss]要求，请检查。");
        }
    }

    private void validateDate(StringBuilder message, InstanceValue instanceValue, Property property) {
        // 日期格式校验
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dstr = instanceValue.getPropertyValue();
        try {
            sdf.parse(dstr);
        } catch (ParseException e) {
            message.append("[" + property.getName() + "]不符合日期格式[yyyy-MM-dd]要求，请检查。");
        }
    }

    private void validateTextarea(StringBuilder message, InstanceValue instanceValue, Property property) {
        try {
            RegularExpression regularExpression = regularExpressionRepository.query(property.getRegexpId());
            if (regularExpression != null && regularExpression.getExpression() != null) {
                Boolean regularReslut = Pattern.matches(regularExpression.getExpression(),
                        instanceValue.getPropertyValue());
                if (!regularReslut) {
                    message.append("属性[" + property.getName() + "]的值不符合[" + regularExpression.getName() + "]格式要求;");
                }
            }
        } catch (Exception e) {
            logger.error("正则校验失败", e);
        }
    }

    private void validateQuote(StringBuilder message, InstanceValue instanceValue, Property property) {
        try {
            Instance instancetemp = instanceRepository.query(Long.parseLong(instanceValue.getPropertyValue()));
            if (instancetemp == null) {
                message.append("属性[" + property.getName() + "]所使用的配置不存在，请检查;");
            } else {
                instanceValue.setPropertyValue(instancetemp.getId().toString());
            }
        } catch (Exception e) {
            logger.error("校验失败", e);
        }
    }

    private void validateTable(StringBuilder message, InstanceValue instanceValue, Property property) {
        List<InstanceGrid> grids = instanceValue.getGrid();
        if (!ListTool.isEmpty(grids)) {
            try {
                List<PropertyItem> propertyItems = propertyItemRepository.queryByPropertyId(property.getId());
                if (!ListTool.isEmpty(propertyItems)) {
                    for (InstanceGrid instanceGrid : grids) {
                        boolean isEmpty = true;
                        for (PropertyItem propertyItem : propertyItems) {
                            if (StringUtils
                                    .isNotEmpty((CharSequence) BeanUtils.getProperties(instanceGrid, propertyItem.getValue()))) {
                                isEmpty = false;
                            }
                        }
                        if (isEmpty) {
                            message.append("[" + property.getName() + "]出现空白行，请修改;");
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("grid校验失败", e);
            }

        }
    }

    private void validateNumber(StringBuilder message, InstanceValue instanceValue, Property property) {
        // 小数自动截取
        if (property.isFloat() && property.getDecimalNum() >= 0
                && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
            try {
                if (null == instanceValue.getPropertyValue() || "null".equals(instanceValue.getPropertyValue())) {
                    instanceValue.setPropertyValue("0");
                }
                BigDecimal bd = new BigDecimal(instanceValue.getPropertyValue());
                bd = bd.setScale(property.getDecimalNum(), BigDecimal.ROUND_HALF_UP);
                instanceValue.setPropertyValue(bd.toString());
            } catch (Exception e) {
                message.append("属性[" + property.getName() + "]为小数，格式输入错误;");
            }
        } else if (property.isInteger() && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
            try {
                BigDecimal bd = new BigDecimal(instanceValue.getPropertyValue());
                bd = bd.setScale(0, BigDecimal.ROUND_HALF_UP);
                instanceValue.setPropertyValue(bd.toString());
            } catch (Exception e) {
                message.append("属性[" + property.getName() + "]为整数，格式输入错误;");
            }
        }
        // 最小值校验
        if (null != property.getMinValue() && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
            try {
                if (property.isInteger()
                        && Long.parseLong(instanceValue.getPropertyValue()) < Long
                        .parseLong(String.valueOf(property.getMinValue()))
                        || property.isFloat() && Float.parseFloat(instanceValue.getPropertyValue()) < Float
                        .parseFloat(String.valueOf(property.getMinValue()))) {
                    message.append("属性[" + property.getName() + "]超出最小值范围[" + property.getMinValue() + "];");
                }
            } catch (Exception e) {
                message.append("属性[" + property.getName() + "]格式输入错误;");
            }

        }
        // 最大值校验
        if (!StringUtils.isEmpty(String.valueOf(property.getMaxValue())) && !StringUtils.isEmpty(instanceValue.getPropertyValue())) {
            try {
                if (property.isInteger()
                        && Long.parseLong(instanceValue.getPropertyValue()) > Long
                        .parseLong(String.valueOf(property.getMaxValue()))
                        || property.isFloat() && Float.parseFloat(instanceValue.getPropertyValue()) > Float
                        .parseFloat(String.valueOf(property.getMaxValue()))) {
                    message.append("属性[" + property.getName() + "]超出最大值范围[" + property.getMaxValue() + "];");
                }
            } catch (Exception e) {
                message.append("属性[" + property.getName() + "]格式输入错误;");
            }

        }
    }

    private void validateSelect(Instance instance, StringBuilder message, InstanceValue instanceValue,
                                Property property) {
        try {
            Boolean have = propertyItemRepository.validateIteam(instance.getModuleId(), instanceValue.getPropertyId(),
                    instanceValue.getPropertyValue());
            if (!have) {
                // 如果给过来的是name 就转成value吧 提高容错
                PropertyItem propertyItem = propertyItemRepository.queryPropertyItemByName(instanceValue.getPropertyId(),
                        instanceValue.getPropertyValue());
                if (propertyItem != null) {
                    instanceValue.setPropertyValue(propertyItem.getValue());
                    have = true;
                }
            }
            if (!have) {
                message.append(property.getName() + " 的选项[" + instanceValue.getPropertyValue() + "]不存在，请检查！");
            }
        } catch (Exception e) {
            logger.error("验证下拉框失败", e);
            message.append("验证下拉框失败;");
        }
    }

    private void validateCheckBox(Instance instance, StringBuilder message, InstanceValue instanceValue,
                                  Property property) {
        try {
            String[] values = instanceValue.getPropertyValue().replace("[", "").replace("]", "").replace(" ", "")
                    .split(",");
            String realValue = "";
            Boolean allRight = true;
            if (property.getItem() == null || property.getItem().isEmpty()) {
                message.append(property.getName() + "未设置选项，请检查模型配置。");
            }
            for (String value : values) {
                Boolean have = false;
                for (PropertyItem propertyItem : property.getItem()) {
                    if (value.equals(propertyItem.getValue()) || value.equals(propertyItem.getName())) {
                        realValue = realValue + "," + propertyItem.getValue();
                        have = true;
                        break;
                    }
                }
                if (!have) {
                    allRight = false;
                    message.append(property.getName() + " 的选项[" + instanceValue.getPropertyValue() + "]不存在，请检查！");
                    break;
                }
            }
            if (allRight) {
                if (realValue.startsWith(",")) {
                    realValue = realValue.substring(1, realValue.length());
                }
                instanceValue.setPropertyValue(realValue);
            }

        } catch (Exception e) {
            logger.error("验证多选失败", e);
            message.append("验证多选失败;");
        }
    }

    /**
     * bname唯一性校验
     *
     * @param bname
     * @param id
     * @return
     */
    private String uniqueValidateByBname(Long moduleId, String bname, Long id) {
        try {
            Instance instance = instanceRepository.uniqueValidateByBname(moduleId, bname, id);
            if (instance != null) {
                return "[" + instance.getBname() + "]已存在,请检查;";
            }
        } catch (Exception e) {
            logger.error("唯一校验出错", e);
            return "系统错误，请稍后重试;";
        }
        return "";
    }

    /**
     * 属性唯一性校验
     *
     * @param moduleId
     * @param instanceId
     * @param propertyCode
     * @param propertyName
     * @param propertyValue
     * @return
     */
    private String uniqueValidateByProperty(Long moduleId, Long instanceId, String propertyCode, String propertyName,
                                            String propertyValue) {
        try {
            Instance instance = instanceRepository.uniqueValidateByProperty(moduleId, instanceId, propertyCode, propertyValue);
            if (instance != null) {
                return "属性[" + propertyName + "]的内容与配置[" + instance.getBname() + "]的该属性重复，请检查;";
            }
        } catch (Exception e) {
            logger.error("唯一校验出错", e);
            return "系统错误，请稍后重试;";
        }
        return "";
    }

}
