package com.boman.web.core.mapper;

import com.alibaba.fastjson.JSONObject;
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.apache.ibatis.jdbc.SQL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

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

import static com.boman.common.core.utils.obj.ObjectUtils.escapeStr;
import static com.boman.domain.constant.FormDataConstant.*;


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

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

    @UpdateProvider(type = JFTaskBusinessMapper.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 id, business_code as businessCode,module_id as moduleId,node_id as nodeId,candidator_id as candidatorId from ${tableName} t where t.business_code = #{businessCode} and t.module_id = #{moduleId} and t.node_id = #{nodeId}")
    ProcessNodeCandidator selectData(@Param("tableName") String tableName, @Param("businessCode") Long businessCode, @Param("moduleId") Long moduleId, @Param("nodeId") Long nodeId);

    @Select("select check_user_id from ${tableName} t where t.id = #{businessCode}")
    String selectBusinessCheckUserId(@Param("tableName") String tableName, @Param("businessCode") Long businessCode);

    @Select("select candidator_id from ${tableName} t where t.business_code = #{businessCode} and module_id = #{moduleId} and node_id = #{nodeId}")
    JSONObject selectNodeData(@Param("tableName") String tableName, @Param("businessCode") Long businessCode, @Param("moduleId") Long moduleId, @Param("nodeId") Long nodeId);

    class SqlProvider {

        private static boolean isNullOrEmpty(String str) {
            return str == null || str.length() == 0 || str.trim().length() == 0;
        }

        private static boolean isNullOrEmpty(JSONObject json) {
            return json == null || json.isEmpty();
        }

        public String insert(Map<String, Object> para) {
            JSONObject model = (JSONObject) para.get("model");
            String tableName = (String) para.get("tableName");
            if (isNullOrEmpty(tableName)) {
                throw new IllegalArgumentException("tableName 无效");
            } else if (isNullOrEmpty(model)) {
                throw new IllegalArgumentException("model 无效");
            } else {
                SQL sql = new SQL();
                Set<String> keySet = model.keySet();
                sql.INSERT_INTO(tableName);

                for (int i = 0; i < model.size(); ++i) {
                    String key = (String) keySet.toArray()[i];
                    sql.VALUES(key, "#{model." + key + "}");
                }

                String sqlStr = sql.toString();
                LOGGER.info("新增的sql语句为: {}, \r\n 新增的数据为: {}", sqlStr, model);
                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(convert(EQ, CHAR, key, 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;
        }

        /**
         * 功能描述: 仅此用来拼装查询条件，不做他用
         *
         * @param queryType  like > < =
         * @param columnType varchar char textarea timestamp
         * @param key        key
         * @param valueObj   valueObj
         * @return java.lang.String
         */
        private String convert(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) + ")";
            }
        }
    }
}
