package com.highdatas.mdm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.highdatas.mdm.entity.SysField;
import com.highdatas.mdm.entity.TableSchemaResult;
import com.highdatas.mdm.mapper.TableInfoMapper;
import com.highdatas.mdm.pojo.CodeMsg;
import com.highdatas.mdm.pojo.Page;
import com.highdatas.mdm.pojo.Result;
import com.highdatas.mdm.pojo.Segment;
import com.highdatas.mdm.service.BaseDataService;
import com.highdatas.mdm.service.ISysFieldService;
import com.highdatas.mdm.util.Constant;
import com.highdatas.mdm.util.ContentBuilder;
import com.highdatas.mdm.util.DbUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kimi
 * @description
 * @date 2019-12-17 12:09
 */

@Service
public class BaseDataServiceImpl implements BaseDataService{
    @Autowired
    TableInfoMapper mapper;
    @Autowired
    ISysFieldService fieldService;


    public Result selectById(String tableName, String id) {
        try{
            EntityWrapper<SysField> sysFieldEntityWrapper = new EntityWrapper<>();
            sysFieldEntityWrapper.eq("table_name", tableName);
            List<SysField> sysFields = fieldService.selectList(sysFieldEntityWrapper);
            JSONObject object = new JSONObject();

            String whereStr = DbUtils.combieOneSegment(Constant.ID, id);
            String fields = getFields(tableName);
            List<Map<String, Object>> select = mapper.select(tableName, fields, whereStr);
            if (select == null || select.size() == 0) {
                return Result.error(CodeMsg.SELECT_ERROR_NOTFOUND);
            }
            else if (select.size() == 1) {

                object.fluentPut("grid", select.get(0));
                object.fluentPut("fields", sysFields);
                return Result.success(object);
            }else {
                object.fluentPut("grid", select);
                object.fluentPut("fields", sysFields);
                return Result.success(object);
            }
        }
        catch (Exception e) {
            return Result.error(CodeMsg.SELECT_ERROR);
        }
    }


    public Result selectList(String tableName){
        return selectList(tableName, Constant.WHERE_DEFAULT);
    }




    public Result selectList(String tableName, String whereSegment) {
        return selectList(tableName, null, whereSegment);
    }



    public Result selectList(String tableName,List<String> fieldList, String whereSegment) {
        try{
            EntityWrapper<SysField> sysFieldEntityWrapper = new EntityWrapper<>();
            sysFieldEntityWrapper.eq("table_name", tableName);
            List<SysField> sysFields = fieldService.selectList(sysFieldEntityWrapper);
            JSONObject object = new JSONObject();

            String fields;
            if (fieldList == null || fieldList.size() == 0) {
                fields = getFields(tableName);
            } else {
                fields = fieldList.stream().collect(Collectors.joining(Constant.COMMA));
            }

            List<Map<String, Object>> select = mapper.select(tableName, fields, whereSegment);
            object.fluentPut("grid", select);
            object.fluentPut("fields", sysFields);
            return  Result.success(object);
        }
        catch (Exception e) {
            return Result.error(CodeMsg.SELECT_ERROR);
        }
    }


    public Result selectList(String tableName, List<String> fields) {
        return selectList(tableName, fields, Constant.WHERE_DEFAULT);
    }

    public Long getCount(String tableName, String whereSegment) {
        try{
            if (StringUtils.isEmpty(whereSegment)) {
                whereSegment = Constant.WHERE_DEFAULT;
            }
            Long count = mapper.getCount(tableName, whereSegment);
            return count;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getFields(String tableName) {
        List<TableSchemaResult> tableField = mapper.getTableField(tableName);
        ContentBuilder contentBuilder = new ContentBuilder(Constant.COMMA);
        for (TableSchemaResult tableSchemaResult : tableField) {
            String fieldName = tableSchemaResult.getFieldName();
            if (fieldName.equalsIgnoreCase(Constant.DEAL)) {
                //DEAL 不给看
                continue;
            }
            contentBuilder.append(fieldName);
        }
        return contentBuilder.toString();
    }


    public Result selectListByPage(String tableName, Integer pageNo, Integer pageSize) {
        return selectListByPage(tableName,Constant.WHERE_DEFAULT,pageNo,pageSize);
    }


    public Result selectListByPage(String tableName, String whereSegment, Integer pageNo) {
        return selectListByPage(tableName,whereSegment,pageNo, null);
    }


    public Result selectListByPage(String tableName, Integer pageNo) {
        return selectListByPage(tableName,Constant.WHERE_DEFAULT,pageNo, null);
    }


    public Result selectListByPage(String tableName, String whereSegment, Integer pageNo, Integer pageSize) {
        return selectListByPage(tableName,null,whereSegment,pageNo,pageSize);
    }


    public Result selectListByPage(String tableName, List<String> fieldList, String whereSegment, Integer pageNo) {
        return selectListByPage(tableName,null,whereSegment,pageNo, null);
    }


    public Result selectListByPage(String tableName, List<String> fieldList, Integer pageNo) {
        return selectListByPage(tableName,null,Constant.WHERE_DEFAULT,pageNo);
    }


    public Result selectListByPage(String tableName,List<String> fieldList, String whereSegment, Integer pageNo, Integer pageSize) {
        Long count = getCount(tableName, whereSegment);
        if (count == null) {
            return Result.error(CodeMsg.SELECT_ERROR);
        }
        Page page = new Page(count);
        if (pageSize != null && pageSize.compareTo(1) != -1) {
            page.setPageSize(pageSize);
        }

        if (page.getPageCount() < pageNo) {
            return Result.error(CodeMsg.SELECT_ERROR_NOTFOUND);
        }
        page.setPageNo(pageNo);

        String limitSQL = page.getLimitSQL();

        String fields;
        if (fieldList == null || fieldList.size() == 0) {
            fields = getFields(tableName);
            fieldList = Arrays.stream(fields.split(Constant.COMMA_TRIM)).collect(Collectors.toList());
        } else {
            fields = fieldList.stream().collect(Collectors.joining(Constant.COMMA));
        }
        EntityWrapper<SysField> sysFieldEntityWrapper = new EntityWrapper<>();
        sysFieldEntityWrapper.eq("table_name", tableName);
        List<SysField> sysFields = fieldService.selectList(sysFieldEntityWrapper);
        JSONObject resultobject = new JSONObject();

        List<Map<String, Object>> maps = mapper.selectByPage(tableName, fields, whereSegment, limitSQL);
        JSONObject object = new JSONObject();

        object.fluentPut("total", page.getRecordCount());
        object.fluentPut("size", page.getPageSize());
        object.fluentPut("pages", page.getPageCount());
        object.fluentPut("current", page.getPageNo());
        object.fluentPut("record", maps);

        resultobject.fluentPut("grid",object);
        resultobject.fluentPut("fields",sysFields);

        return Result.success(resultobject);
    }


    public Result insert(String tableName, String fields, String values) {
        try {
            String[] split = fields.split(Constant.SEMICOLON);
            List<String> fieldNameList = Arrays.stream(split).map(s -> s.trim()).collect(Collectors.toList());
            ContentBuilder builder = new ContentBuilder(Constant.COMMA);
            Object parse = JSON.parse(values);
            List<String> ids = new ArrayList<>();
            if (parse instanceof JSONObject){
                JSONObject jsonObject = (JSONObject) parse;
                String id = appendOneValue(jsonObject, fieldNameList, builder);
                ids.add(id);
                String sqlValues  = builder.toString();
                mapper.insert(tableName, fields, sqlValues);
                return Result.success(CodeMsg.INSERT_SUCCESS);
            } else if (parse instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) parse;
                int size = jsonArray.size();
                for (int i = 0; i < size; i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    ids.add(appendOneValue(jsonObject, fieldNameList, builder));

                }
                String sqlValues = builder.toString();
                mapper.insert(tableName, fields, sqlValues);
                return Result.success(ids);
            } else {
                return Result.error(CodeMsg.INSERT_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.INSERT_ERROR);
        }

    }

    public Result insert(String tableName, String json) {
        try {
            List<TableSchemaResult> tableFieldList = mapper.getTableField(tableName);
            List<String> fieldNameList = tableFieldList.stream().map(TableSchemaResult::getFieldName).collect(Collectors.toList());
            String fields = tableFieldList.stream().map(TableSchemaResult::getFieldName).collect(Collectors.joining(Constant.COMMA));

            ContentBuilder builder = new ContentBuilder(Constant.COMMA);
            Object parse = JSON.parse(json);
            List<String> ids = new ArrayList<>();
            if (parse instanceof JSONObject){
                JSONObject jsonObject = (JSONObject) parse;
                ids.add(appendOneValue(jsonObject, fieldNameList, builder));
                String sqlValues  = builder.toString();
                mapper.insert(tableName, fields, sqlValues);
                return Result.success(CodeMsg.INSERT_SUCCESS);
            } else if (parse instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) parse;
                int size = jsonArray.size();
                for (int i = 0; i < size; i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    ids.add(appendOneValue(jsonObject, fieldNameList, builder));
                }
                String sqlValues = builder.toString();
                mapper.insert(tableName, fields, sqlValues);
                return Result.success(ids);
            } else {
                return Result.error(CodeMsg.INSERT_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.INSERT_ERROR);
        }

    }

    private String appendOneValue(JSONObject jsonObject, List<String> fieldNameList, ContentBuilder builder) {
        String id = null;
        builder.append("(");
        boolean first = true;
        for (int i = 0; i < fieldNameList.size(); i++) {
            String fieldName = fieldNameList.get(i);

            Object value = jsonObject.get(fieldName);
            if (fieldName.equalsIgnoreCase(Constant.ID) && value == null) {
                id =  DbUtils.getUUID();
                value = id;
            }
            if (value == null) {
                continue;
            }
            if (value instanceof String) {
                value = DbUtils.quotedStr(value);
            }
            if (first) {
                builder.appendOnly(String.valueOf(value));
                first = false;
            }  else {
                builder.append(value);
            }
        }
        //deal
        builder.append(1);

        builder.appendOnly(")");
        return id;
    }


    public Result updateById(String tableName, String fieldsSegment, String id, boolean total) {
        String whereStr = DbUtils.combieOneSegment(Constant.ID, id);
        return update(tableName, fieldsSegment,whereStr, total);
    }


    public Result update(String tableName, String fieldsSegment, boolean total) {
        String whereSegment = Constant.WHERE_DEFAULT;
        return update(tableName, fieldsSegment,whereSegment, total);
    }


    public Result update(String tableName, String fieldsSegment, String whereSegment) {
        try {
            ContentBuilder builder = new ContentBuilder(Constant.COMMA);
            JSONObject jsonObject = JSONObject.parseObject(fieldsSegment);
            List<TableSchemaResult> tableFieldResultList = mapper.getTableField(tableName);
            for (TableSchemaResult tableSchemaResult : tableFieldResultList) {
                String dbType = tableSchemaResult.getDbType();
                String fieldName = tableSchemaResult.getFieldName();
                Object o = jsonObject.get(fieldName);
                String javaTypeStr = DbUtils.toSqlToJava(dbType);
                Segment segment;
                if ("string".equalsIgnoreCase(javaTypeStr.trim())) {
                    segment = new Segment(fieldName, String.valueOf(o));
                } else {
                    segment = new Segment(fieldName, o);
                }
                builder.append(segment.toString());
            }
            String updateSegment = builder.toString();
            mapper.update(tableName, updateSegment, whereSegment);
            return Result.success(CodeMsg.UPDATE_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.UPDATE_ERROR);
        }
    }


    public Result update(String tableName, String fieldsSegment, String whereSegment, boolean total) {
        try {
            ContentBuilder builder = new ContentBuilder(Constant.COMMA);
            JSONObject jsonObject = JSONObject.parseObject(fieldsSegment);
            List<TableSchemaResult> tableFieldResultList = mapper.getTableField(tableName);
            if (total) {
                for (TableSchemaResult tableSchemaResult : tableFieldResultList) {
                    String dbType = tableSchemaResult.getDbType();
                    String fieldName = tableSchemaResult.getFieldName();
                    Object o = jsonObject.get(fieldName);
                    String javaTypeStr = DbUtils.toSqlToJava(dbType);
                    Segment segment;
                    if (o == null) {
                        continue;
                    }
                    if ("string".equalsIgnoreCase(javaTypeStr.trim())) {
                        segment = new Segment(fieldName, String.valueOf(o));
                    } else {
                        if (fieldName.equalsIgnoreCase(Constant.DEAL)) {
                            segment = new Segment(fieldName, 1);
                        } else {
                            segment = new Segment(fieldName, o);
                        }
                    }
                    builder.append(segment.toString());
                }
            } else {
                Set<String> fieldSet = jsonObject.keySet();
                for (String fieldName : fieldSet) {
                    List<TableSchemaResult> collect = tableFieldResultList.stream().filter(tableSchemaResult -> tableSchemaResult.getFieldName().equalsIgnoreCase(fieldName)).collect(Collectors.toList());
                    TableSchemaResult tableSchemaResult = collect.get(0);
                    String dbType = tableSchemaResult.getDbType();
                    Object o = jsonObject.get(fieldName);
                    String javaTypeStr = DbUtils.toSqlToJava(dbType);
                    Segment segment;
                    if ("string".equalsIgnoreCase(javaTypeStr.trim())) {
                        segment = new Segment(fieldName, String.valueOf(o));
                    } else {
                        if (fieldName.equalsIgnoreCase(Constant.DEAL)) {
                            segment = new Segment(fieldName, 1);
                        } else {
                            segment = new Segment(fieldName, o);
                        }
                    }
                    builder.append(segment.toString());
                }
            }

            String updateSegment = builder.toString();
            mapper.update(tableName, updateSegment, whereSegment);
            return Result.success(CodeMsg.UPDATE_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.UPDATE_ERROR);
        }
    }


    public Result delete(String tableName) {
        return  delete(tableName, Constant.WHERE_DEFAULT);
    }


    public Result deleteById(String tableName, String id) {
        String whereStr = DbUtils.combieOneSegment(Constant.ID, id);
        return  delete(tableName, whereStr);
    }

    public Result delete(String tableName, String whereSegment) {
        try {
            mapper.delete(tableName, whereSegment);
            return Result.success(CodeMsg.DELETE_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.DELETE_ERROR);
        }
    }
}