package com.yunzhupaas.base.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.yunzhupaas.base.entity.VisualdevEntity;
import com.yunzhupaas.base.entity.VisualdevReleaseEntity;
import com.yunzhupaas.base.mapper.VisualdevMapper;
import com.yunzhupaas.base.model.PaginationVisualdev;
import com.yunzhupaas.base.model.dbtable.vo.DbFieldVO;
import com.yunzhupaas.base.model.form.VisualTableModel;
import com.yunzhupaas.base.service.*;
import com.yunzhupaas.base.util.ConcurrencyUtils;
import com.yunzhupaas.base.util.VisualDevTableCre;
import com.yunzhupaas.base.util.VisualUtils;
import com.yunzhupaas.constant.YunzhupaasConst;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.database.constant.DbAliasConst;
import com.yunzhupaas.database.model.dbfield.DbFieldModel;
import com.yunzhupaas.database.model.dbfield.base.DbFieldModelBase;
import com.yunzhupaas.database.model.dbtable.DbTableFieldModel;
import com.yunzhupaas.database.model.entity.DbLinkEntity;
import com.yunzhupaas.database.util.DataSourceUtil;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.model.OnlineDevData;
import com.yunzhupaas.model.visualJson.*;
import com.yunzhupaas.model.visualJson.analysis.FormAllModel;
import com.yunzhupaas.model.visualJson.analysis.FormEnum;
import com.yunzhupaas.model.visualJson.analysis.FormMastTableModel;
import com.yunzhupaas.model.visualJson.analysis.RecursionForm;
import com.yunzhupaas.model.visualJson.config.ConfigModel;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.RandomUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts;
import lombok.SneakyThrows;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author 云筑产品开发平台组
 * @version V3.1.0
 * @copyright 深圳市乐程软件有限公司（http://www.szlecheng.cn）
 * @date 2024/3/16
 */
@Service
public class VisualdevServiceImpl extends SuperServiceImpl<VisualdevMapper, VisualdevEntity>
        implements VisualdevService {

    @Autowired
    private VisualDevTableCre visualDevTableCreUtil;
    @Autowired
    private ConcurrencyUtils concurrencyUtils;
    @Autowired
    private DbTableServiceImpl dbTableService;
    @Autowired
    private DbLinkService dblinkService;
    @Autowired
    private DataSourceUtil dataSourceUtil;
    @Autowired
    private FilterService filterService;
    @Autowired
    private VisualdevReleaseService visualdevReleaseService;

    @Override
    public List<VisualdevEntity> getList(PaginationVisualdev paginationVisualdev) {
        // 定义变量判断是否需要使用修改时间倒序
        boolean flag = false;
        QueryWrapper<VisualdevEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(VisualdevEntity::getId, VisualdevEntity::getCategory, VisualdevEntity::getEnCode,
                VisualdevEntity::getFullName,
                VisualdevEntity::getCreatorTime, VisualdevEntity::getCreatorUserId, VisualdevEntity::getLastModifyTime,
                VisualdevEntity::getLastModifyUserId,
                VisualdevEntity::getEnabledMark, VisualdevEntity::getSortCode, VisualdevEntity::getState,
                VisualdevEntity::getType,
                VisualdevEntity::getWebType, VisualdevEntity::getVisualTables, VisualdevEntity::getPlatformRelease);

        if (!StringUtil.isEmpty(paginationVisualdev.getKeyword())) {
            flag = true;
            queryWrapper.lambda().and(t -> t.like(VisualdevEntity::getFullName, paginationVisualdev.getKeyword())
                    .or().like(VisualdevEntity::getEnCode, paginationVisualdev.getKeyword()));
        }

        if (ObjectUtil.isNotEmpty(paginationVisualdev.getType())) {
            queryWrapper.lambda().eq(VisualdevEntity::getType, paginationVisualdev.getType());
        }

        if (StringUtil.isNotEmpty(paginationVisualdev.getCategory())) {
            flag = true;
            queryWrapper.lambda().eq(VisualdevEntity::getCategory, paginationVisualdev.getCategory());
        }

        // ---功能类型查询
        if (paginationVisualdev.getWebType() != null) {// 普通表单
            flag = true;
            queryWrapper.lambda().eq(VisualdevEntity::getWebType, paginationVisualdev.getWebType());
        }

        // 状态
        if (StringUtil.isNotEmpty(paginationVisualdev.getIsRelease())) {
            flag = true;
            List<String> releaseList = Arrays.asList(paginationVisualdev.getIsRelease().split(","));
            if (releaseList.size() > 1) {
                List<Integer> jsonToList = JsonUtil.getJsonToList(releaseList, Integer.class);
                queryWrapper.lambda().in(VisualdevEntity::getState, jsonToList);
            } else if (releaseList.size() == 1) {
                queryWrapper.lambda().eq(VisualdevEntity::getState, paginationVisualdev.getIsRelease());
            }

        }

        // 排序
        queryWrapper.lambda().orderByAsc(VisualdevEntity::getSortCode).orderByDesc(VisualdevEntity::getCreatorTime);
        if (flag) {
            queryWrapper.lambda().orderByDesc(VisualdevEntity::getLastModifyTime);
        }
        Page<VisualdevEntity> page = new Page<>(paginationVisualdev.getCurrentPage(),
                paginationVisualdev.getPageSize());
        IPage<VisualdevEntity> userPage = this.page(page, queryWrapper);
        return paginationVisualdev.setData(userPage.getRecords(), page.getTotal());
    }

    @Override
    public List<VisualdevEntity> getPageList(PaginationVisualdev paginationVisualdev) {
        QueryWrapper<VisualdevReleaseEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(
                VisualdevReleaseEntity::getId,
                VisualdevReleaseEntity::getFullName,
                VisualdevReleaseEntity::getType,
                VisualdevReleaseEntity::getEnCode);
        // 1-集成助手，查询列表， 2-流程表单查询，纯表单和列表
        if (paginationVisualdev.getWebType() != null) {
            List<Integer> webType = ImmutableList.of(1, 2, 4);
            if (Objects.equals(paginationVisualdev.getWebType(), 1)) {
                webType = ImmutableList.of(2);
            } else if (Objects.equals(paginationVisualdev.getWebType(), 2)) {
                webType = ImmutableList.of(1, 2);
            }
            queryWrapper.lambda().in(VisualdevReleaseEntity::getWebType, webType);
        }
        if (!StringUtil.isEmpty(paginationVisualdev.getKeyword())) {
            queryWrapper.lambda().like(VisualdevReleaseEntity::getFullName, paginationVisualdev.getKeyword());
        }
        if (ObjectUtil.isNotEmpty(paginationVisualdev.getType())) {
            queryWrapper.lambda().eq(VisualdevReleaseEntity::getType, paginationVisualdev.getType());
        }
        if (StringUtil.isNotEmpty(paginationVisualdev.getCategory())) {
            queryWrapper.lambda().eq(VisualdevReleaseEntity::getCategory, paginationVisualdev.getCategory());
        }
        // 排序
        queryWrapper.lambda().orderByAsc(VisualdevReleaseEntity::getSortCode)
                .orderByDesc(VisualdevReleaseEntity::getCreatorTime);
        Page<VisualdevReleaseEntity> page = new Page<>(paginationVisualdev.getCurrentPage(),
                paginationVisualdev.getPageSize());
        IPage<VisualdevReleaseEntity> userPage = visualdevReleaseService.page(page, queryWrapper);
        List<VisualdevEntity> list = JsonUtil.getJsonToList(userPage.getRecords(), VisualdevEntity.class);
        return paginationVisualdev.setData(list, page.getTotal());
    }

    @Override
    public List<VisualdevEntity> getList() {
        QueryWrapper<VisualdevEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(VisualdevEntity::getSortCode).orderByDesc(VisualdevEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public VisualdevEntity getInfo(String id) {
        if (StringUtil.isBlank(id))
            return null;
        QueryWrapper<VisualdevEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(VisualdevEntity::getId, id);
        return this.getOne(queryWrapper);
    }

    @Override
    public VisualdevEntity getReleaseInfo(String id) {
        VisualdevReleaseEntity visualdevReleaseEntity = visualdevReleaseService.getById(id);
        VisualdevEntity visualdevEntity = null;
        if (visualdevReleaseEntity != null) {
            visualdevEntity = JsonUtil.getJsonToBean(visualdevReleaseEntity, VisualdevEntity.class);
        }
        if (visualdevEntity == null) {
            visualdevEntity = getById(id);
        }
        return visualdevEntity;
    }

    @Override
    public Map<String, String> getTableMap(String formData) {
        Map<String, String> tableMap = new HashMap<>();
        if (StringUtil.isEmpty(formData)) {
            return tableMap;
        }
        FormDataModel formDataModel = JsonUtil.getJsonToBean(formData, FormDataModel.class);
        String fields = formDataModel.getFields();
        List<FieLdsModel> list = JsonUtil.getJsonToList(fields, FieLdsModel.class);
        list.forEach(item -> {
            this.solveTableName(item, tableMap);
        });
        return tableMap;
    }

    private void solveTableName(FieLdsModel item, Map tableMap) {
        ConfigModel config = item.getConfig();
        if (config != null) {
            List<FieLdsModel> children = config.getChildren();
            if ("table".equals(config.getYunzhupaasKey())) {
                if (children != null && children.size() > 0) {
                    FieLdsModel fieLdsModel = children.get(0);
                    String parentVModel = item.getVModel();
                    String relationTable = fieLdsModel.getConfig().getRelationTable();
                    if (StringUtil.isNotBlank(relationTable)) {
                        tableMap.put(parentVModel, relationTable);
                    }
                }
            }
            if (children != null) {
                children.forEach(item2 -> {
                    this.solveTableName(item2, tableMap);
                });
            }
        }
    }

    ;

    @Override
    @SneakyThrows
    public Boolean create(VisualdevEntity entity) {
        if (StringUtil.isEmpty(entity.getId())) {
            entity.setId(RandomUtil.uuId());
        }
        if (OnlineDevData.FORM_TYPE_DEV.equals(entity.getType())) {
            FormDataModel formDataModel = JsonUtil.getJsonToBean(entity.getFormData(), FormDataModel.class);
            if (formDataModel != null) {
                // 是否开启安全锁
                int primaryKeyPolicy = formDataModel.getPrimaryKeyPolicy();

                // 判断是否要创表
                List<TableModel> tableModels = JsonUtil.getJsonToList(entity.getVisualTables(), TableModel.class);
                // 有表
                if (tableModels.size() > 0) {
                    Map<String, String> tableMap = this.getTableMap(entity.getFormData());
                    // 保存app,pc过滤配置
                    filterService.saveRuleList(entity.getId(), entity, 1, 1, tableMap);

                    for (TableModel tableModel : tableModels) {
                        Boolean isAutoIncre = this.getPrimaryDbField(entity.getDbLinkId(), tableModel.getTable());
                        // 1:雪花ID 2:自增ID
                        if (primaryKeyPolicy == 1) {
                            if (isAutoIncre != null && isAutoIncre) {
                                throw new WorkFlowException(MsgCode.VS022.get(tableModel.getTable()));
                            }
                        } else if (primaryKeyPolicy == 2) {
                            if (isAutoIncre == null || !isAutoIncre) {
                                throw new WorkFlowException(MsgCode.VS023.get(tableModel.getTable()));
                            }
                        }
                    }

                    try {
                        String tableJsonMap = addDbFileds(entity.getDbLinkId(), tableModels, formDataModel);
                        if (StringUtil.isNotEmpty(tableJsonMap)) {
                            entity.setVisualTables(tableJsonMap);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        entity.setEnabledMark(0);
        entity.setState(0);
        entity.setCreatorTime(new Date());
        entity.setCreatorUserId(UserProvider.getLoginUserId());
        entity.setLastModifyTime(null);
        entity.setLastModifyUserId(null);
        this.setIgnoreLogicDelete().removeById(entity.getId());
        boolean result = this.setIgnoreLogicDelete().saveOrUpdate(entity);
        this.clearIgnoreLogicDelete();
        return result;
    }

    /**
     * 数据库表，添加字段
     *
     * @param dbLinkId      数据链接id
     * @param visualTables  表列表
     * @param formDataModel 表单属性
     * @throws Exception
     */
    private String addDbFileds(String dbLinkId, List<TableModel> visualTables, FormDataModel formDataModel)
            throws Exception {
        if (CollectionUtils.isEmpty(visualTables))
            return null;

        List<Map<String, Object>> tableJsonMap = new ArrayList<>();
        Boolean concurrencyLock = formDataModel.getConcurrencyLock();
        Boolean logicalDelete = formDataModel.getLogicalDelete();
        // 在各个表创建多租户字段强
        for (TableModel tableModel : visualTables) {
            boolean isMainTable = tableModel.getTypeId().equals("1");
            List<DbFieldModel> dbFieldModelList = dbTableService.getFieldList(dbLinkId, tableModel.getTable());
            List<DbFieldModelBase> fieldList = JsonUtil.getJsonToList(dbFieldModelList, DbFieldModelBase.class);
            List<DbFieldModel> addList = new ArrayList<>();
            DbLinkEntity dbLink = dblinkService.getInfo(dbLinkId);
            String type = dbLink != null ? dbLink.getDbType() : dataSourceUtil.getDbType();
            concurrencyUtils.createTenantId(fieldList, type, addList);
            if (logicalDelete) {
                concurrencyUtils.creDeleteMark(fieldList, type, addList);
            }
            if (isMainTable && concurrencyLock) {
                concurrencyUtils.createVersion(fieldList, type, addList);
            }
            if (isMainTable) {
                // 流程字段强制生成
                concurrencyUtils.createFlowEngine(fieldList, type, addList);
                concurrencyUtils.createFlowTaskId(fieldList, type, addList);
            }
            concurrencyUtils.addFileds(tableModel.getTable(), dbLinkId, addList);
            List<DbFieldVO> voList = new ArrayList<>();
            List<DbFieldModelBase> listAll = new ArrayList<>();
            listAll.addAll(fieldList);
            listAll.addAll(addList);
            for (DbFieldModelBase item : listAll) {
                DbFieldVO tableFields = new DbFieldVO();
                tableFields.setField(item.getField());
                tableFields.setFieldName(item.getComment());
                tableFields.setDataType(item.getDataType());
                tableFields.setDataLength(item.getLength());
                tableFields.setPrimaryKey(DbAliasConst.PRIMARY_KEY.getNum(item.getIsPrimaryKey()));
                tableFields.setAllowNull(DbAliasConst.ALLOW_NULL.getNum(item.getNullSign()));
                tableFields.setAutoIncrement(DbAliasConst.AUTO_INCREMENT.getNum(item.getIsAutoIncrement()));
                tableFields.setIdentity(DbAliasConst.AUTO_INCREMENT.getNum(item.getIsAutoIncrement()));
                voList.add(tableFields);
            }
            Map<String, Object> stringObjectMap = JsonUtil.entityToMap(tableModel);
            stringObjectMap.put("fields", voList);
            tableJsonMap.add(stringObjectMap);
        }
        return JsonUtil.getObjectToString(tableJsonMap);
    }

    @Override
    public boolean update(String id, VisualdevEntity entity) throws Exception {
        entity.setId(id);
        entity.setLastModifyUserId(UserProvider.getUser().getUserId());
        if (OnlineDevData.FORM_TYPE_DEV.equals(entity.getType())) {
            // 代码生成修改时就要生成字段
            FormDataModel formDataModel = JsonUtil.getJsonToBean(entity.getFormData(), FormDataModel.class);
            if (formDataModel != null) {
                int primaryKeyPolicy = formDataModel.getPrimaryKeyPolicy();
                // 判断是否要创表
                List<TableModel> visualTables = JsonUtil.getJsonToList(entity.getVisualTables(), TableModel.class);
                // 有表
                if (visualTables.size() > 0) {
                    if (formDataModel != null) {
                        try {
                            // 字段强制生成
                            String tableJsonMap = addDbFileds(entity.getDbLinkId(), visualTables, formDataModel);
                            if (StringUtil.isNotEmpty(tableJsonMap)) {
                                entity.setVisualTables(tableJsonMap);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        // 判断自增是否匹配
                        concurrencyUtils.checkAutoIncrement(primaryKeyPolicy, entity.getDbLinkId(), visualTables);
                    }
                }
            }
        }
        return this.updateById(entity);
    }

    @Override
    public Integer getObjByEncode(String encode, Integer type) {
        QueryWrapper<VisualdevEntity> visualWrapper = new QueryWrapper<>();
        visualWrapper.lambda().eq(VisualdevEntity::getEnCode, encode).eq(VisualdevEntity::getType, type);
        Integer count = (int) this.count(visualWrapper);
        return count;
    }

    @Override
    public Integer getCountByName(String name, Integer type) {
        QueryWrapper<VisualdevEntity> visualWrapper = new QueryWrapper<>();
        visualWrapper.lambda().eq(VisualdevEntity::getFullName, name).eq(VisualdevEntity::getType, type);
        Integer count = (int) this.count(visualWrapper);
        return count;
    }

    @Override
    public void createTable(VisualdevEntity entity) throws WorkFlowException {
        FormDataModel formDataModel = JsonUtil.getJsonToBean(entity.getFormData(), FormDataModel.class);
        // 是否开启安全锁
        Boolean concurrencyLock = formDataModel.getConcurrencyLock();
        int primaryKeyPolicy = formDataModel.getPrimaryKeyPolicy();
        Boolean logicalDelete = formDataModel.getLogicalDelete();

        Map<String, Object> formMap = JsonUtil.stringToMap(entity.getFormData());
        List<FieLdsModel> list = JsonUtil.getJsonToList(formMap.get("fields"), FieLdsModel.class);
        JSONArray formJsonArray = JsonUtil.getJsonToJsonArray(String.valueOf(formMap.get("fields")));
        List<TableModel> visualTables = JsonUtil.getJsonToList(entity.getVisualTables(), TableModel.class);

        List<FormAllModel> formAllModel = new ArrayList<>();
        RecursionForm recursionForm = new RecursionForm();
        recursionForm.setTableModelList(visualTables);
        recursionForm.setList(list);
        FormCloumnUtil.recursionForm(recursionForm, formAllModel);

        String tableName = "mt" + RandomUtil.uuId();

        String dbLinkId = entity.getDbLinkId();
        VisualTableModel model = new VisualTableModel(formJsonArray, formAllModel, tableName, dbLinkId,
                entity.getFullName(), concurrencyLock, primaryKeyPolicy, logicalDelete);
        List<TableModel> tableModelList = visualDevTableCreUtil.tableList(model);
        formMap.put("fields", formJsonArray);
        // 更新
        entity.setFormData(JsonUtil.getObjectToString(formMap));
        entity.setVisualTables(JsonUtil.getObjectToString(tableModelList));
    }

    @Override
    public Boolean getPrimaryDbField(String linkId, String table) throws Exception {
        DbTableFieldModel dbTableModel = dbTableService.getDbTableModel(linkId, table);
        List<DbFieldModel> data = dbTableModel.getDbFieldModelList();
        DbFieldModel dbFieldModel = data.stream().filter(DbFieldModel::getIsPrimaryKey).findFirst().orElse(null);
        if (dbFieldModel != null) {
            return dbFieldModel.getIsAutoIncrement() != null && dbFieldModel.getIsAutoIncrement();
        } else {
            return null;
        }
    }

    @Override
    public List<VisualdevEntity> selectorList() {
        QueryWrapper<VisualdevEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(
                VisualdevEntity::getId,
                VisualdevEntity::getFullName,
                VisualdevEntity::getWebType,
                VisualdevEntity::getType,
                VisualdevEntity::getCategory);
        return this.list(queryWrapper);
    }

    @Override
    public List<TableFields> storedFieldList(VisualdevEntity entity) {
        List<TableFields> resultList = new ArrayList<>();
        if (entity != null) {
            // 是否存在关联数据库
            try {
                DbLinkEntity linkEntity = null;
                if (StringUtil.isNotEmpty(entity.getDbLinkId())) {
                    linkEntity = dblinkService.getInfo(entity.getDbLinkId());
                }
                // 获取主表
                List<TableModel> listTable = JsonUtil.getJsonToList(entity.getVisualTables(), TableModel.class);
                String mainTable = listTable.stream().filter(t -> "1".equals(t.getTypeId())).findFirst().orElse(null)
                        .getTable();
                // 获取主键
                String pKeyName = VisualUtils.getpKey(linkEntity, mainTable);
                resultList.add(new TableFields(pKeyName, "表单主键"));
                FormDataModel formData = JsonUtil.getJsonToBean(entity.getFormData(), FormDataModel.class);
                List<FieLdsModel> list = JsonUtil.getJsonToList(formData.getFields(), FieLdsModel.class);
                List<FormAllModel> formAllModel = new ArrayList<>();
                RecursionForm recursionForm = new RecursionForm();
                recursionForm.setTableModelList(JsonUtil.getJsonToList(entity.getVisualTables(), TableModel.class));
                recursionForm.setList(list);
                FormCloumnUtil.recursionForm(recursionForm, formAllModel);
                List<FormAllModel> mast = formAllModel.stream()
                        .filter(t -> FormEnum.mast.getMessage().equals(t.getYunzhupaasKey()))
                        .collect(Collectors.toList());
                // 列表子表数据
                List<FormAllModel> mastTable = formAllModel.stream()
                        .filter(t -> FormEnum.mastTable.getMessage().equals(t.getYunzhupaasKey()))
                        .collect(Collectors.toList());
                for (FormAllModel item : mast) {
                    FieLdsModel fieLdsModel = item.getFormColumnModel().getFieLdsModel();
                    addField(fieLdsModel.getVModel(), fieLdsModel, resultList);
                }
                for (FormAllModel item : mastTable) {
                    FormMastTableModel formMastTableModel = item.getFormMastTableModel();
                    FieLdsModel fieLdsModel = formMastTableModel.getMastTable().getFieLdsModel();
                    addField(formMastTableModel.getVModel(), fieLdsModel, resultList);
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        return resultList;
    }

    /**
     * 添加字段（统一过滤条件）
     *
     * @param realVmodel
     * @param fieLdsModel
     * @param resultList
     */
    private static void addField(String realVmodel, FieLdsModel fieLdsModel, List<TableFields> resultList) {
        List<String> list = Arrays.asList(YunzhupaasKeyConsts.COM_INPUT, YunzhupaasKeyConsts.BILLRULE);
        if (StringUtil.isNotEmpty(fieLdsModel.getVModel())
                && list.contains(fieLdsModel.getConfig().getYunzhupaasKey())) {
            resultList.add(new TableFields(realVmodel + YunzhupaasConst.FIELD_SUFFIX_YUNZHUPAASID,
                    fieLdsModel.getConfig().getLabel()));
        }
    }
}
