package com.boman.web.core.mapper;

import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.obj.ObjectUtils;
import com.boman.domain.dto.UpdateDto;
import com.boman.domain.jflow.ProcessNodeCandidator;
import com.boman.web.core.utils.ColumnUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

import static com.boman.common.core.utils.obj.ObjectUtils.escapeStr;
import static com.boman.common.core.utils.obj.ObjectUtils.isEmpty;
import static com.boman.domain.constant.FormDataConstant.*;
import static com.mysql.cj.util.StringUtils.isNullOrEmpty;

/**
 * 流程针对业务数据层面接口
 *
 *
 * @author zhong.h
 */
@Mapper
@Component
public interface JFTaskBusinessMapper {
    Logger LOGGER = LoggerFactory.getLogger(JFTaskBusinessMapper.class);

    @InsertProvider(type = StandardMapper.SqlProvider.class, method = "insert")
    int insert(@Param("tableName") String var1, @Param("model") JSONObject var2);

    @UpdateProvider(type = StandardMapper.SqlProvider.class, method = "update")
    int updateByIdList(@Param("tableName") String tableName, @Param("pkName") String pkName
            , @Param("idList") List<Long> idList, @Param("model") JSONObject models);


    @Select("select * from process_node_candidators t where t.business_code = #{businessCode} and t.module_id = #{moduleId} and t.node_id = #{nodeId}")
    ProcessNodeCandidator selectData(@Param("businessCode") Long businessCode, @Param("moduleId") Long moduleId, @Param("nodeId") Long nodeId);

    @UpdateProvider(type = SqlProvider.class, method = "updateBusinessData")
    int updateBusinessData(@Param("tableName") String tableName, @Param("packCommitData") JSONObject packCommitData
            , @Param("packColCondition") JSONObject packColCondition);

    class SqlProvider {

        public String insertList(Map<String, Object> para) {
            List<JSONObject> dataList = (List<JSONObject>) para.get("dataList");
            String tableName = (String) para.get("tableName");
            if (isNullOrEmpty(tableName)) {
                throw new IllegalArgumentException("tableName 无效");
            }

            if (ObjectUtils.isEmpty(dataList)) {
                throw new IllegalArgumentException("需要插入的数据为空");
            }

            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("insert into ").append(tableName).append(" ( ");
            JSONObject keySet = dataList.get(0);
            stringBuilder.append(String.join(", ", keySet.keySet()));
            stringBuilder.append(" ) ").append("values ");

            for (JSONObject data : dataList) {
                StringBuilder values = new StringBuilder();
                values.append(" ( ");
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    values.append("#{model.").append(entry.getKey()).append("}, ");
                }

                String beforeLast = StringUtils.substringBeforeLast(values.toString(), ", ");
                stringBuilder.append(beforeLast).append(" ) ");
            }

            String sqlStr = stringBuilder.toString();
            LOGGER.info("批量新增的sql语句为: {} \r\n 新增的数据为: {}", sqlStr, dataList);
            return sqlStr;
        }

        public String update(Map<String, Object> para) {
            String tableName = (String) para.get("tableName");
            String pkName = (String) para.get("pkName");
            List<Long> idList = (List<Long>) para.get("idList");
            JSONObject models = (JSONObject) para.get("model");

            StringBuilder wholeSql = new StringBuilder();
            wholeSql.append("update ").append(tableName).append(" set ");
            for (Map.Entry<String, Object> entry : models.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                wholeSql.append(key).append(" = ").append(value).append(" , ");
            }

            wholeSql = new StringBuilder(StringUtils.substringBeforeLast(wholeSql.toString(), ","));
            wholeSql.append(" where ").append(pkName).append(" in ( ");

            for (int i = 0; i < idList.size(); ++i) {
                wholeSql.append(String.format("#{idList[%d]}", i));
                wholeSql.append(",");
            }

            wholeSql.setCharAt(wholeSql.length() - 1, ')');
            String sqlStr = wholeSql.toString();
            LOGGER.info("批量更新的sql语句为: {} \r\n 更改的数据为: {} \r\n idList: {}", sqlStr, models, idList);
            return sqlStr;
        }

        public String updateBusinessData(Map<String, Object> para) {
            String tableName = (String) para.get("tableName");
            JSONObject packCommitData = (JSONObject) para.get("packCommitData");
            JSONObject packColCondition = (JSONObject) para.get("packColCondition");

            StringBuilder wholeSql = new StringBuilder();
            wholeSql.append("update ").append(tableName).append(" set ");

            for (Map.Entry<String, Object> entry : packCommitData.entrySet()) {
                String key = entry.getKey();
                Object valueObj = entry.getValue();
                List<String> types = ((List<String>) valueObj);
                /** {@link com.boman.web.core.utils.ColumnUtils.packColCondition} 这里是拼参数的地方 **/
                Object value = types.get(0);
                String queryType = types.get(1);
                String columnType = types.get(2);
                wholeSql.append(key).append(covert(queryType, columnType, key, value)).append(" , ");
            }

            wholeSql = new StringBuilder(StringUtils.substringBeforeLast(wholeSql.toString(), " , "));
            packCondition(packColCondition, wholeSql);

            String sqlStr = wholeSql.toString();
            LOGGER.info("通用的更新sql语句为: {} \r\n 提交的数据为: {} \r\n 条件为: {}", sqlStr, packCommitData, packColCondition);
            return sqlStr;
        }

        /**
         * 功能描述: 判断传过来的值是否需要转义
         *
         * @param packCondition 封装的条件
         * @param wholeSql      sql
         */
        private void packCondition(JSONObject packCondition, StringBuilder wholeSql) {
            if (isEmpty(packCondition)) {
                return;
            }

            wholeSql.append(" where ");
            StringBuilder conditionSql = new StringBuilder();
            for (Map.Entry<String, Object> entry : packCondition.entrySet()) {
                String key = entry.getKey();
                Object valueObj = entry.getValue();
                List<String> types = ((List<String>) valueObj);
                /** {@link com.boman.web.core.utils.ColumnUtils.packColCondition} 这里是拼参数的地方 **/
                Object value = types.get(0);

                conditionSql.append(key).append(covert(EQ, "NUMBER", key, value)).append(" and ");
            }

            wholeSql.append(StringUtils.substringBeforeLast(conditionSql.toString(), " and"));
        }

        /**
         * 功能描述: 仅此用来拼装查询条件，不做他用
         *
         * @param queryType  like > < =
         * @param columnType varchar char textarea timestamp
         * @param key        key
         * @param valueObj   valueObj
         * @return java.lang.String
         */
        private String covert(String queryType, String columnType, String key, Object valueObj) {
            // false 不需要转义
            boolean needEscape = columnType.contains(VARCHAR) || columnType.contains(CHAR) || columnType.contains(DATETIME) || columnType.contains(TIMESTAMP);
            Object value;
            switch (queryType) {
                case EQ:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " = " + value;
                case LIKE:
                    return " like concat('%', #{condition." + key + "}, '%')";
                case NE:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " != " + value;
                case GT:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " > " + value;
                case GTE:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " >= " + value;
                case LT:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " < " + value;
                case LTE:
                    value = needEscape ? escapeStr(String.valueOf(valueObj)) : valueObj;
                    return " <= " + value;
                default:
                    // in
                    List<Object> list = valueObj instanceof List ? ((List<Object>) valueObj) : Lists.newArrayList(valueObj);
                    return " in (" + ColumnUtils.joinList(list) + ")";
            }
        }
    }
}
