package com.jeeplus.centerservice.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.jeeplus.centerservice.dto.WorkAttachmentDto;
import com.jeeplus.centerservice.service.ccpm.flow.FlowRequest;
import com.jeeplus.sys.service.dto.UserDTO;
import com.jeeplus.utils.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

public class GenerateFormUtil {

    @Resource
    private FlowRequest flowRequest;

    /**
     * 创建栅栏
     * @return
     */
    public static Map<String, Object> createGrid() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "grid");
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "grid_" + key); // 字段标识
        map.put("columns", new ArrayList<>()); // 包含字段
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("gutter", 0); // 栅格间隔
        optionsMap.put("justify", "start"); // 水平排列方式
        optionsMap.put("align", "top"); // 垂直排列方式
        optionsMap.put("hidden", false); // 是否隐藏
        optionsMap.put("flex", true); // flex布局
        optionsMap.put("customClass", ""); // 自定义样式类名
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建列 12
     * @return
     */
    public static Map<String, Object> createCol_12() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "col");
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("list", new ArrayList<>()); // 包含字段
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("span", 15); // 占位
        optionsMap.put("offset", 0);
        optionsMap.put("push", 0);
        optionsMap.put("pull", 0);
        optionsMap.put("xs", 12);
        optionsMap.put("sm", 12);
        optionsMap.put("md", 12);
        optionsMap.put("lg", 12);
        optionsMap.put("xl", 12);
        optionsMap.put("customClass", "");
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建列 24
     * @return
     */
    public static Map<String, Object> createCol_24() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "col");
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("list", new ArrayList<>()); // 包含字段
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("span", 24); // 占位
        optionsMap.put("offset", 0);
        optionsMap.put("push", 0);
        optionsMap.put("pull", 0);
        optionsMap.put("xs", 24);
        optionsMap.put("sm", 24);
        optionsMap.put("md", 24);
        optionsMap.put("lg", 24);
        optionsMap.put("xl", 24);
        optionsMap.put("customClass", "");
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建单行文本
     * @return
     */
    public static Map<String, Object> createInput() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "input");
        map.put("name", "单行文本"); // input表单label值
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "input_" + key); // 字段标识
        Map<String, Object> optionsMap = publicOptions();
        optionsMap.put("defaultValue", ""); // 默认值
        optionsMap.put("dataType", ""); // 数据类型
        optionsMap.put("dataTypeCheck", false);// 是否启用数据类型验证
        optionsMap.put("dataTypeMessage", "");// 数据类型验证错误信息
        optionsMap.put("pattern", ""); // 正则表达式
        optionsMap.put("patternCheck", false); // 是否启用正则表达式验证
        optionsMap.put("patternMessage", "");// 正则表达式验证错误信息
        optionsMap.put("validatorCheck", false);// 是否启用自定验证
        optionsMap.put("validator", "");// 自定义验证函数
        optionsMap.put("placeholder", "");// 占位内容
        optionsMap.put("showPassword", false);// 显示密码
        optionsMap.put("clearable", false); // 是否可清除
        optionsMap.put("maxlength", ""); // 最大输入长度
        optionsMap.put("showWordLimit", false); // 是否显示输入长度
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建多行文本
     * @return
     */
    public static Map<String, Object> createTextarea() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "textarea");
        map.put("name", "多行文本"); // textarea表单label值
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "textarea_" + key); // 字段标识
        Map<String, Object> optionsMap = publicOptions();
        optionsMap.put("defaultValue", ""); // 默认值
        optionsMap.put("pattern", ""); // 正则表达式
        optionsMap.put("patternCheck", false); // 是否启用正则表达式验证
        optionsMap.put("patternMessage", "");// 正则表达式验证错误信息
        optionsMap.put("validatorCheck", false);// 是否启用自定验证
        optionsMap.put("validator", "");// 自定义验证函数
        optionsMap.put("placeholder", "");// 占位内容
        optionsMap.put("maxlength", ""); // 最大输入长度
        optionsMap.put("showWordLimit", false); // 是否显示输入长度
        optionsMap.put("rows", 2); // 输入框行数
        optionsMap.put("autosize", false); // 高度是否自适应
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建分割线
     * @return
     */
    public static Map<String, Object> createDivider() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "divider");
        map.put("name", "分割线"); // 分割线标题
        map.put("icon", "el-icon-warning-outline"); // 图标
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "divider_" + key); // 字段标识
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("hidden", false); // 是否隐藏
        optionsMap.put("contentPosition", "left"); // 标题位置
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建子表单
     * @return
     */
    public static Map<String, Object> createTable() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "table");
        map.put("tableColumns", new ArrayList<>()); // 多列字段数据
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "table_" + key); // 字段标识
        Map<String, Object> optionsMap = publicOptions();
        optionsMap.put("isLabelWidth", true);// 标签宽度是否自定义
        optionsMap.put("labelWidth", 0);// 标签宽度，isLabelWidth 为 true 时生效
        optionsMap.put("disabled", true);// 是否禁用
        optionsMap.put("defaultValue", new ArrayList<>()); // 默认值
        optionsMap.put("validatorCheck", false); // 是否启用自定验证
        optionsMap.put("validator", ""); // 自定义验证函数
        optionsMap.put("paging", false); // 是否分页
        optionsMap.put("pageSize", 10); // 每页显示数目
        optionsMap.put("isAdd", false); // 是否可新增行
        optionsMap.put("isDelete", false); // 是否可删除行
        optionsMap.put("showControl", false); // 展示控制按钮
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 创建文字
     * @return
     */
    public static Map<String, Object> createText() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "text");
        map.put("name", "文字"); // 标题/表头
        String key = UUID.randomUUID().toString();
        map.put("key", key); // key
        map.put("model", "text_" + key); // 字段标识
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("defaultValue", ""); // 默认值
        optionsMap.put("customClass", ""); // 自定义样式类名
        optionsMap.put("labelWidth", 0); // 标签宽度，isLabelWidth 为 true 时生效
        optionsMap.put("isLabelWidth", false); // 标签宽度是否自定义
        optionsMap.put("hidden", false); // 是否隐藏
        optionsMap.put("dataBind", true); // 是否进行数据绑定
        map.put("options", optionsMap); // 配置
        return map;
    }

    /**
     * 一些公共字段，不适用所有组件
     * @return
     */
    public static Map<String, Object> publicOptions() {
        Map<String, Object> optionsMap = new HashMap<>();
        optionsMap.put("customClass", "");// 自定义样式类名
        optionsMap.put("isLabelWidth", false);// 标签宽度是否自定义。值为false时，宽度跟随表单配置(config)中的labelWidth属性
        optionsMap.put("labelWidth", 100);// 标签宽度，isLabelWidth 为 true 时生效
        optionsMap.put("hidden", false);// 是否隐藏
        optionsMap.put("disabled", false);// 是否禁用
        optionsMap.put("dataBind", true);// 是否进行数据绑定
        optionsMap.put("required", false); // 是否必填
        optionsMap.put("requiredMessage", ""); // 必填验证错误信息
        optionsMap.put("width", "100%"); // 宽度
        return optionsMap;
    }

    /**
     * 表单默认配置
     * @return
     */
    public static Map<String, Object> defaultConfig() {
        Map<String, Object> map = new HashMap<>();
        map.put("labelWidth", 80); // 表单标签（label）宽度
        map.put("labelPosition", "right"); // 标签对齐方式
        map.put("size", "default"); // 组件尺寸
        map.put("customClass", ""); // 自定义样式表类名
        map.put("customJs", ""); // 自定义JS
        map.put("eventType", "1"); // 自定义JS执行时机  1：保存前执行 2：保存后执行
        map.put("ui", "element"); // 表单使用的组件库 Element: "element", Ant Design: "antd"
        map.put("layout", "horizontal");
        map.put("labelCol", 3); // label所占比例
        map.put("actions", new ArrayList<>());
        map.put("width", "100%"); // 表单宽度
        map.put("hideLabel", false); // 是否隐藏label
        map.put("hideErrorMessage", false); // 是否隐藏error信息
        return map;
    }

    // 将map数据转换为前端需要的json数据
    public static Map<String, Object> convertToForm(Map<String, Object> req) {
        /*Map<String,Object> req = new LinkedHashMap<>();
        // input
        Map<String,Object> key1 = new HashMap<String,Object>();
        key1.put("type", "input");
        key1.put("label", "创建人");
        key1.put("disabled", "1"); // 1：禁用。其他或者不赋值则不禁用
        req.put(JSON.toJSONString(key1),"测试人员");
        // textarea
        Map<String,Object> key4 = new HashMap<String,Object>();
        key4.put("type", "textarea");
        key4.put("label", "测试多行文本");
        key4.put("disabled", "1");
        req.put(JSON.toJSONString(key4),"测试多行文本");
        // table
        Map<String,Object> key6 = new HashMap<String,Object>();
        key6.put("type", "table");
        key6.put("label", "测试表格1");
        Map<String,String> tableColumns2 = new LinkedHashMap<>();
        tableColumns2.put("text1","字段011");
        tableColumns2.put("text2","字段02");
        tableColumns2.put("text3","字段03");
        key6.put("tableColumns", tableColumns2);
        List<Map<String,Object>> tableList2 = new ArrayList<>();
        Map<String,Object> tableMap12 = new HashMap<>();
        tableMap12.put("text1","测试数据1112");
        tableMap12.put("text2","测试数据12");
        tableMap12.put("text3","测试数据13");
        tableList2.add(tableMap12);
        Map<String,Object> tableMap22 = new HashMap<>();
        tableMap22.put("text1","测试数据21");
        tableMap22.put("text2","测试数据22");
        tableMap22.put("text3","测试数据23");
        tableList2.add(tableMap22);
        req.put(JSON.toJSONString(key6),tableList2);*/
        // 以上为测试数据

        // 返回结果
        Map<String, Object> respMap = new HashMap<>();
        // 初始化表单配置
        Map<String, Object> defaultConfig = defaultConfig();
        // 根据参数生成表单数据
        List<Map<String, Object>> formList = new ArrayList<>();

        req.forEach((k,v)->{
            // 注：LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序。但是因为中间将LinkedHashMap转成了json字符串，
            // 然后用fastjson转json对像进一步处理数据。这里的底层会默认采用hashmap的那一套对map数据又重新排序一次
            // 为防止数据又重新排序，所以在这里转换时使用Feature.OrderedField来解决此问题
            LinkedHashMap<String, Object> key = JSONObject.parseObject(k, LinkedHashMap.class, Feature.OrderedField);
            String type = key.get("type").toString(); // 表单类型
            switch (type) {
                case "input": // 单行文本
                    boolean createNew = true; // 是否创建新的栅栏，放入col_12的input
                    if (formList.size() > 0) { // 表单列表已经有表单，则进入如下操作
                        // 获取表单列表中最后一个表单
                        Map<String, Object> lastForm = formList.get(formList.size() - 1);
                        // 判断最后一个表单是否为栅栏
                        if ("grid".equals(lastForm.get("type").toString())) {
                            int size = Integer.parseInt(lastForm.get("size").toString()); // 获取栅栏中元素的占位
                            List<Object> gridColumns = JSONArray.parseArray(JSON.toJSONString(lastForm.get("columns")));
                            if (size == 12) { // 元素的占位是12，则不创建新的栅栏，直接放入col_12的input
                                Map<String, Object> newGrid = setCol_12_Input(lastForm,gridColumns,key,v);
                                formList.set(formList.size() - 1, newGrid);
                                createNew = false;
                            }
                        }
                    }
                    if (createNew) { // createNew为true，表示需要创建新的栅栏，放入col_12的input
                        Map<String, Object> newGrid = setCol_12_Input(createGrid(),new ArrayList<>(),key,v);
                        formList.add(newGrid);
                    }
                    break;
                case "textarea": // 多行文本
                    Map<String, Object> newGrid = setCol_24_Textarea(createGrid(), new ArrayList<>(), key, v);
                    formList.add(newGrid);
                    break;
                case "table": // 子表单，也就是表格
                    Map<String, Object> divider = createDivider(); // 开始创建分割线
                    if (ObjectUtil.isNotEmpty(key.get("label"))) {
                        divider.put("name", key.get("label").toString());
                    } else {
                        divider.put("name", "详情列表");
                    }
                    formList.add(divider); // 添加分割线
                    Map<String, Object> table = createTable(); // 开始创建表格
                    List<Map<String, Object>> tableColumnList = new ArrayList<>();
                    // 表头获取
                    LinkedHashMap<String, Object> tableColumnsMap = JSONObject.parseObject(JSON.toJSONString(key.get("tableColumns")), LinkedHashMap.class, Feature.OrderedField);
                    tableColumnsMap.forEach((columnKey,columnValue) -> {
                        Map<String, Object> text = createText();
                        text.put("name",columnValue.toString()); // 列头的名称
                        text.put("model",columnKey); // 列表数据绑定的字段
                        String textWidth = getTextWidthByValue(columnKey,v); // 根据该列下的值来判断此列的宽度应该设置为多少
                        if (StringUtils.isNotBlank(textWidth)) {
                            Map<String, Object> textOptionsMap = JSONObject.parseObject(JSON.toJSONString(text.get("options")), Map.class);
                            textOptionsMap.put("width",textWidth); // 设置当前列的宽度
                            text.put("options",textOptionsMap);
                        }
                        tableColumnList.add(text);
                    });
                    table.put("tableColumns",tableColumnList);
                    // 列表数据
                    List<Map<String, Object>> defaultValues =(List) JSONArray.parseArray(JSON.toJSONString(v)); // 通过集合中map的key对应表头的model来进行数据的绑定
                    Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(table.get("options")));
                    optionsMap.put("defaultValue",defaultValues); // 绑定列表的数据
                    table.put("options",optionsMap);
                    // 表格
                    formList.add(table);
                    break;
                case "files": // 附件
                    if (ObjectUtil.isNotEmpty(key.get("label"))) {
                        respMap.put("filesLabel",key.get("label").toString()); // 附件label
                    } else {
                        respMap.put("filesLabel","附件"); // 附件label
                    }
                    List<WorkAttachmentDto> files = new ArrayList<>();
                    if (ObjectUtil.isNotEmpty(v)) {
                        List<Map<String, Object>> fileList = (List)JSONArray.parseArray(JSON.toJSONString(v));
                        for (Map<String, Object> fileMap : fileList) {
                            WorkAttachmentDto attachmentDto = new WorkAttachmentDto();
                            UserDTO userDTO = new UserDTO();
                            if (ObjectUtil.isNotEmpty(fileMap.get("attachmentName"))) { // 附件名称
                                attachmentDto.setName(fileMap.get("attachmentName").toString());
                            }
                            if (ObjectUtil.isNotEmpty(fileMap.get("createName"))) { // 创建人
                                userDTO.setName(fileMap.get("createName").toString());
                            }
                            if (ObjectUtil.isNotEmpty(fileMap.get("createDate"))) { // 创建时间
                                attachmentDto.setCreateTime(DateUtil.parse(fileMap.get("createDate").toString()));
                            }
                            if (ObjectUtil.isNotEmpty(fileMap.get("url"))) { // 文件地址
                                attachmentDto.setUrl(fileMap.get("url").toString());
                            }
                            if (ObjectUtil.isNotEmpty(fileMap.get("temporaryUrl"))) { // 文件临时地址
                                attachmentDto.setLsUrl(fileMap.get("temporaryUrl").toString());
                            }
                            attachmentDto.setCreateBy(userDTO);
                            files.add(attachmentDto);
                        }
                    }
                    respMap.put("files",files); // 附件
                    break;
                case "processInstanceId":
                    respMap.put("processInstanceId", v.toString()); // processInstanceId
                    break;
                default:
                    break;
            }
        });
        respMap.put("list",formList); // 表单数据
        respMap.put("config",defaultConfig); // 表单配置
        return respMap;
    }

    /**
     * 根据该列下的值来判断此列的宽度应该设置为多少
     * @param columnKey
     * @param value
     * @return
     */
    public static String getTextWidthByValue(Object columnKey, Object value) {
        String column = columnKey.toString();
        AtomicReference<String> width = new AtomicReference<>("");
        List<Map<String, Object>> list = (List)JSONObject.parseArray(JSONObject.toJSONString(value));

        for (Map<String, Object> map : list) {
            map.forEach((k,v) -> {
                if (k.equals(column)) {
                    String columnValue = v.toString();
                    if (StringUtils.isNotBlank(columnValue)) {
                        if (columnValue.length() >= 7) {
                            width.set("150px");
                        }
                        if (columnValue.length() >= 12) {
                            width.set("200px");
                        }
                        if (columnValue.length() >= 18) {
                            width.set("300px");
                        }
                        if (columnValue.length() >= 24) {
                            width.set("400px");
                        }
                    }
                }
            });
        }
        return width.get();
    }

    /**
     * 创建列col_12，将input放到列中
     * 最后将列放到栅栏中返回
     */
    public static Map<String, Object> setCol_12_Input(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
        Map<String, Object> newGrid = grid; // 栅栏
        List<Object> newGridColumns = setColInput("15", gridColumns, key, value);
        newGrid.put("columns", newGridColumns);
        if (ObjectUtil.isNotEmpty(newGrid.get("size"))) { // 设置栅栏当前包含元素的占位
            int size = Integer.parseInt(newGrid.get("size").toString());
            newGrid.put("size",size + 12);
        } else {
            newGrid.put("size",12);
        }
        return newGrid;
    }

    /**
     * 创建列col_24，将input放到列中
     * 最后将列放到栅栏中返回
     */
    public static Map<String, Object> setCol_24_Input(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
        Map<String, Object> newGrid = grid; // 栅栏
        List<Object> newGridColumns = setColInput("24", gridColumns, key, value);
        newGrid.put("columns", newGridColumns);
        newGrid.put("size",24); // 设置栅栏当前包含元素的占位
        return newGrid;
    }

    /**
     * 创建列，将input放到列中
     * @param size 值为“24”时创建col_24，其他默认为col_12
     */
    public static List<Object> setColInput(String size, List<Object> gridColumns, Map<String, Object> key, Object value) {
        Map<String, Object> col = createCol_12(); // 列 12
        if ("24".equals(size)) {
            col = createCol_24(); // 列 24
        }
        Map<String, Object> input = createInput(); // input
        Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(input.get("options"))); // 获取input的默认options
        if (CollectionUtil.isEmpty(gridColumns)) {
            gridColumns = new ArrayList<>();
        }
        List<Object> newGridColumns = gridColumns;
        List<Map<String, Object>> colList = new ArrayList<>();
        if (ObjectUtil.isEmpty(key.get("label"))) {
            input.put("name", "单行文本");
        } else {
            input.put("name", key.get("label").toString()); // input表单的label值
        }
        if (ObjectUtil.isNotEmpty(key.get("disabled")) && "1".equals(key.get("disabled").toString())) {
            optionsMap.put("disabled", true); // 禁用
        }
        optionsMap.put("defaultValue", value); // input表单的value值
        input.put("options", optionsMap);
        colList.add(input);
        col.put("list", colList);
        newGridColumns.add(col);
        return newGridColumns;
    }

    /**
     * 创建列col_24，将textarea放到列中
     * 最后将列放到栅栏中返回
     */
    public static Map<String, Object> setCol_24_Textarea(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
        Map<String, Object> newGrid = grid; // 栅栏
        Map<String, Object> col = createCol_24(); // 列
        Map<String, Object> textarea = createTextarea(); // textarea
        Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(textarea.get("options"))); // 获取textarea的默认options
        if (CollectionUtil.isEmpty(gridColumns)) {
            gridColumns = new ArrayList<>();
        }
        List<Object> newGridColumns = gridColumns;
        List<Map<String, Object>> colList = new ArrayList<>();
        if (ObjectUtil.isEmpty(key.get("label"))) {
            textarea.put("name", "多行文本");
        } else {
            textarea.put("name", key.get("label").toString()); // textarea表单的label值
        }
        if (ObjectUtil.isNotEmpty(key.get("disabled")) && "1".equals(key.get("disabled").toString())) {
            optionsMap.put("disabled", true); // 禁用
        }
        optionsMap.put("defaultValue", value); // textarea表单的value值
        textarea.put("options", optionsMap);
        colList.add(textarea);
        col.put("list", colList);
        newGridColumns.add(col);
        newGrid.put("columns", newGridColumns);
        newGrid.put("size",24); // 设置栅栏当前包含元素的占位
        return newGrid;
    }

}
