package com.cm.common.plugin.service.dynamic.impl;

import com.cm.common.base.AbstractService;
import com.cm.common.exception.*;
import com.cm.common.plugin.dao.dynamic.IDynamicDataDao;
import com.cm.common.plugin.enums.dynamic.FieldRequireTypeEnum;
import com.cm.common.plugin.enums.dynamic.FieldTypeEnum;
import com.cm.common.plugin.pojo.dtos.dynamic.DynamicFormDTO;
import com.cm.common.plugin.service.dynamic.IDynamicDataService;
import com.cm.common.plugin.service.dynamic.IDynamicFormService;
import com.cm.common.plugin.service.dynamic.IDynamicTableService;
import com.cm.common.pojo.ListPage;
import com.cm.common.result.SuccessResult;
import com.cm.common.result.SuccessResultList;
import com.cm.common.utils.HashMapUtil;
import com.cm.common.utils.RegexUtil;
import com.cm.common.utils.UUIDUtil;
import com.cm.common.utils.WStringUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.KeyValue;
import org.apache.commons.collections.keyvalue.DefaultKeyValue;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: DynamicDataServiceImpl
 * @Description: 动态数据
 * @Author: WangGeng
 * @Date: 2019/12/4 16:35
 * @Version: 1.0
 **/
@Service
public class DynamicDataServiceImpl extends AbstractService implements IDynamicDataService {

    @Autowired
    private IDynamicDataDao dynamicDataDao;
    @Autowired
    private IDynamicFormService dynamicFormService;

    @Override
    public SuccessResult saveDynamicData(String tableName, Map<String, Object> params) throws SearchException, SaveException {
        return saveDynamicData(null, tableName, params);
    }

    @Override
    public SuccessResult saveDynamicData(String token, String tableName, Map<String, Object> params) throws SearchException, SaveException {
        List<DynamicFormDTO> dynamicFormDTOs = dynamicFormService.listDynamicForm(tableName);
        LOG.debug("校验参数");
        requireData(params, dynamicFormDTOs);
        LOG.debug("获取插入列和插入值");
        List<String> insertFieldList = new ArrayList<>();
        List<Object> insertValueList = new ArrayList<>();
        for (DynamicFormDTO dynamicFormDTO : dynamicFormDTOs) {
            insertFieldList.add(WStringUtil.lowerUpper2UnderLine(dynamicFormDTO.getFieldName()));
            insertValueList.add(params.get(dynamicFormDTO.getFieldName()));
        }
        params.clear();
        setUpdateBaseInfo(tableName, params);
        params.put("uuidValue", UUIDUtil.getUUID());
        params.put("insertFieldList", insertFieldList);
        params.put("insertValueList", insertValueList);
        if (token != null) {
            setSaveInfo(token, params);
        } else {
            setSaveInfo(params);
        }
        dynamicDataDao.saveDynamicData(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult removeDynamicData(String tableName, String ids) throws RemoveException {
        return removeDynamicData(null, tableName, ids);
    }

    @Override
    public SuccessResult removeDynamicData(String token, String tableName, String ids) throws RemoveException {
        Map<String, Object> params = getHashMap(7);
        setUpdateBaseInfo(tableName, params);
        params.put("idArray", Arrays.asList(ids.split("_")));
        if (token != null) {
            setUpdateInfo(token, params);
        } else {
            setUpdateInfo(params);
        }
        dynamicDataDao.removeDynamicData(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult updateDynamicData(String tableName, String id, Map<String, Object> params) throws UpdateException {
        return updateDynamicData(null, tableName, id, params);
    }

    @Override
    public SuccessResult updateDynamicData(String token, String tableName, String id, Map<String, Object> params) throws UpdateException {
        List<KeyValue> updateFieldValueList = listUpdateFieldValueList(tableName, params);
        params.clear();
        setUpdateBaseInfo(tableName, params);
        params.put("uuidValue", id);
        params.put("updateFieldValueList", updateFieldValueList);
        if (token != null) {
            setUpdateInfo(token, params);
        } else {
            setUpdateInfo(params);
        }
        dynamicDataDao.updateDynamicData(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult updateDynamicJoinData(String tableName, String joinKey, String joinId, Map<String, Object> params) {
        return updateDynamicJoinData(null, tableName, joinKey, joinId, params);
    }

    @Override
    public SuccessResult updateDynamicJoinData(String token, String tableName, String joinKey, String joinId, Map<String, Object> params) throws UpdateException {
        List<KeyValue> updateFieldValueList = listUpdateFieldValueList(tableName, params);
        params.clear();
        setUpdateBaseInfo(tableName, params);
        params.put("joinKey", WStringUtil.lowerUpper2UnderLine(joinKey));
        params.put("joinId", joinId);
        params.put("updateFieldValueList", updateFieldValueList);
        if (token != null) {
            setUpdateInfo(token, params);
        } else {
            setUpdateInfo(params);
        }
        dynamicDataDao.updateDynamicJoinData(params);
        return new SuccessResult();
    }

    /**
     * 更新字段列表
     *
     * @param tableName
     * @param params
     * @return
     */
    private List<KeyValue> listUpdateFieldValueList(String tableName, Map<String, Object> params) {
        List<DynamicFormDTO> dynamicFormDTOs = dynamicFormService.listDynamicForm(tableName);
        LOG.debug("校验参数");
        requireData(params, dynamicFormDTOs);
        LOG.debug("获取修改键值");
        List<KeyValue> updateFieldValueList = new ArrayList<>();
        for (DynamicFormDTO dynamicFormDTO : dynamicFormDTOs) {
            updateFieldValueList.add(new DefaultKeyValue(WStringUtil.lowerUpper2UnderLine(dynamicFormDTO.getFieldName()), params.get(dynamicFormDTO.getFieldName())));
        }
        return updateFieldValueList;
    }

    @Override
    public List<Map<String, Object>> listDynamicData(String tableName, Map<String, Object> params) {
        setSearchBaseListInfo(tableName, params);
        List<Map<String, Object>> listDynamicData = dynamicDataDao.listDynamicData(params);
        resetDynamicDataKey2LowerUpper(listDynamicData);
        return listDynamicData;
    }

    @Override
    public List<Map<String, Object>> listDynamicDataDefault(String tableName, Map<String, Object> params) {
        setSearchBaseListInfo(tableName, params);
        return dynamicDataDao.listDynamicData(params);
    }

    @Override
    public SuccessResultList<List<Map<String, Object>>> listPageDynamicData(String tableName, ListPage listPage) throws SearchException {
        setSearchBaseListInfo(tableName, listPage.getParams());
        PageHelper.startPage(listPage.getPage(), listPage.getRows());
        List<Map<String, Object>> listDynamicData = dynamicDataDao.listDynamicData(listPage.getParams());
        resetDynamicDataKey2LowerUpper(listDynamicData);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(listDynamicData);
        return new SuccessResultList<>(listDynamicData, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public Map<String, Object> getDynamicData(String tableName, String id) throws SearchException {
        Map<String, Object> params = getHashMap(0);
        setSearchBaseGetInfo(tableName, params);
        params.put("uuidValue", id);
        Map<String, Object> dynamicData = dynamicDataDao.getDynamicData(params);
        resetDynamicDataKey2LowerUpper(dynamicData);
        return dynamicData;
    }

    @Override
    public Map<String, Object> getDynamicJoinData(String tableName, String joinKey, String joinId) throws SearchException {
        Map<String, Object> params = getHashMap(0);
        setSearchBaseGetInfo(tableName, params);
        params.put("joinKey", WStringUtil.lowerUpper2UnderLine(joinKey));
        params.put("joinId", joinId);
        Map<String, Object> dynamicData = dynamicDataDao.getDynamicJoinData(params);
        if (Objects.isNull(dynamicData)) {
            dynamicData = getHashMap(0);
        }
        resetDynamicDataKey2LowerUpper(dynamicData);
        return dynamicData;
    }

    @Override
    public List<Map<String, Object>> listDynamicJoinData(String tableName, String joinKey, List<String> joinIds) throws SearchException {
        Map<String, Object> params = getHashMap(0);
        setSearchBaseGetInfo(tableName, params);
        params.put("joinKey", WStringUtil.lowerUpper2UnderLine(joinKey));
        params.put("joinIds", joinIds);
        List<Map<String, Object>> dynamicDatas = dynamicDataDao.listDynamicJoinData(params);
        if (Objects.isNull(dynamicDatas)) {
            dynamicDatas = new ArrayList<>();
        }
        for (Map<String, Object> dynamicData : dynamicDatas) {
            resetDynamicDataKey2LowerUpper(dynamicData);
        }
        return dynamicDatas;
    }

    @Override
    public void resetDynamicDataKey2LowerUpper(List<Map<String, Object>> listDynamicData) {
        for (Map<String, Object> dynamicData : listDynamicData) {
            resetDynamicDataKey2LowerUpper(dynamicData);
        }
    }

    /**
     * 设置查询列表基础信息
     *
     * @param tableName
     * @param params
     */
    private void setSearchBaseListInfo(String tableName, Map<String, Object> params) {
        List<DynamicFormDTO> dynamicFormDTOs = dynamicFormService.listDynamicForm(tableName);
        // 列表显示字段
        List<Map<String, Object>> listShowFieldList = dynamicFormService.listListShowField(dynamicFormDTOs);
        params.put("listShowFieldList", listShowFieldList);
        if (isCheckboxExist(listShowFieldList)) {
            params.put("isCheckboxExist", "exist");
        }
        // 联表字段列表
        List<Map<String, Object>> listJoinTableField = dynamicFormService.listJoinTableField(dynamicFormDTOs);
        if (!listJoinTableField.isEmpty()) {
            HashMapUtil.bubbleSort(listJoinTableField, "joinTableSort", true, true);
            params.put("listJoinTableField", listJoinTableField);
        }
        setSearchBaseInfo(tableName, params);
    }

    /**
     * checkbox是否存在
     *
     * @param listShowFieldList
     * @return
     */
    private boolean isCheckboxExist(List<Map<String, Object>> listShowFieldList) {
        boolean isCheckboxExist = false;
        for (Map<String, Object> showFieldList : listShowFieldList) {
            if (StringUtils.equals(FieldTypeEnum.CHECKBOX.getValue(), showFieldList.get("fieldType").toString())) {
                isCheckboxExist = true;
                break;
            }
        }
        return isCheckboxExist;
    }

    /**
     * 设置查询详情基础信息
     *
     * @param tableName
     * @param params
     */
    private void setSearchBaseGetInfo(String tableName, Map<String, Object> params) {
        List<String> formShowFieldList = dynamicFormService.listFormShowField(tableName);
        params.put("formShowFieldList", formShowFieldList);
        setSearchBaseInfo(tableName, params);
    }

    /**
     * 设置查询基础信息
     *
     * @param tableName
     * @param params
     */
    private void setSearchBaseInfo(String tableName, Map<String, Object> params) {
        String lowerUnderLineTableName = WStringUtil.lowerUpper2UnderLine(tableName);
        params.put("tableName", String.format("%s%s", IDynamicTableService.DYNAMIC_TABLE_PREFIX, lowerUnderLineTableName));
        params.put("uuidField", String.format("%s_id", lowerUnderLineTableName));
    }

    /**
     * 设置更新基础信息
     *
     * @param tableName
     * @param params
     */
    private void setUpdateBaseInfo(String tableName, Map<String, Object> params) {
        String lowerUnderLineTableName = WStringUtil.lowerUpper2UnderLine(tableName);
        params.put("tableName", String.format("%s%s", IDynamicTableService.DYNAMIC_TABLE_PREFIX, lowerUnderLineTableName));
        params.put("uuidField", String.format("%s_id", lowerUnderLineTableName));
    }

    /**
     * 设置表字段为驼峰式
     *
     * @param dynamicData
     */
    private void resetDynamicDataKey2LowerUpper(Map<String, Object> dynamicData) {
        List<String> keyList = new ArrayList<>();
        for (Map.Entry<String, Object> keyValue : dynamicData.entrySet()) {
            keyList.add(keyValue.getKey());
        }
        for (String key : keyList) {
            String newKey = WStringUtil.underLine2LowerUpper(key);
            if (!StringUtils.equals(key, newKey)) {
                dynamicData.put(WStringUtil.underLine2LowerUpper(key), dynamicData.get(key));
                dynamicData.remove(key);
            }
        }
    }

    /**
     * 验证数据
     *
     * @param params
     * @param dynamicFormDTOs
     */
    private void requireData(Map<String, Object> params, List<DynamicFormDTO> dynamicFormDTOs) {
        if (params.isEmpty()) {
            throw new SaveException("新增数据为空");
        }
        if (dynamicFormDTOs == null || dynamicFormDTOs.isEmpty()) {
            throw new SaveException("新增表列为空");
        }
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            for (DynamicFormDTO dynamicFormDTO : dynamicFormDTOs) {
                // 表单显示，并且字段相同，有校验类型则校验参数
                if (dynamicFormDTO.getFormShow() == 1
                        && StringUtils.equals(key, dynamicFormDTO.getFieldName())
                        && !StringUtils.equals(FieldRequireTypeEnum.NONE.getValue(), dynamicFormDTO.getVerifyType())) {
                    if (value == null || StringUtils.isBlank(value.toString())) {
                        throw new ParamsException(String.format("%s不能为空", dynamicFormDTO.getFieldExplain()));
                    }
                    if (StringUtils.equals(FieldRequireTypeEnum.PHONE.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (RegexUtil.isPhone(value.toString())) {
                            throw new ParamsException(String.format("%s必须为手机号码格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.EMAIL.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (RegexUtil.isEmail(value.toString())) {
                            throw new ParamsException(String.format("%s必须为邮箱格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.URL.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (RegexUtil.isEmail(value.toString())) {
                            throw new ParamsException(String.format("%s必须为链接格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.NUMBER.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (NumberUtils.isNumber(value.toString())) {
                            throw new ParamsException(String.format("%s必须为数字格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.DATE.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (RegexUtil.isDate(value.toString())) {
                            throw new ParamsException(String.format("%s必须为日期格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.IDENTITY.getValue(), dynamicFormDTO.getVerifyType())) {
                        if (RegexUtil.isIdentity(value.toString())) {
                            throw new ParamsException(String.format("%s必须为身份证格式", dynamicFormDTO.getFieldExplain()));
                        }
                    } else if (StringUtils.equals(FieldRequireTypeEnum.CUSTOM.getValue(), dynamicFormDTO.getVerifyType())) {
                        Pattern pattern = Pattern.compile(dynamicFormDTO.getVerifyRegular());
                        if (RegexUtil.isMatch(pattern, value.toString())) {
                            throw new ParamsException(String.format("%s不符合自定义格式", dynamicFormDTO.getFieldExplain()));
                        }
                    }
                    break;
                }
            }
        }
    }

}
