package com.yunzhupaas.onlinedev.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.yunzhupaas.base.entity.VisualdevEntity;
import com.yunzhupaas.base.mapper.FlowFormDataMapper;
import com.yunzhupaas.base.model.ColumnDataModel;
import com.yunzhupaas.base.model.OnlineImport.VisualdevModelDataInfoVO;
import com.yunzhupaas.base.model.VisualConst;
import com.yunzhupaas.base.model.form.ModuleFormModel;
import com.yunzhupaas.base.service.DbLinkService;
import com.yunzhupaas.base.util.FlowFormDataUtil;
import com.yunzhupaas.base.util.FormPublicUtils;
import com.yunzhupaas.database.model.entity.DbLinkEntity;
import com.yunzhupaas.database.util.ConnUtil;
import com.yunzhupaas.database.util.DynamicDataSourceUtil;
import com.yunzhupaas.model.visualJson.*;
import com.yunzhupaas.model.visualJson.analysis.*;
import com.yunzhupaas.onlinedev.model.OnlineInfoModel;
import com.yunzhupaas.onlinedev.service.VisualDevInfoService;
import com.yunzhupaas.onlinedev.util.onlineDevUtil.OnlinePublicUtils;
import com.yunzhupaas.onlinedev.util.onlineDevUtil.OnlineSwapDataUtils;
import com.yunzhupaas.permissions.PermissionInterfaceImpl;
import com.yunzhupaas.util.*;
import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts;
import lombok.Cleanup;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import org.mybatis.dynamic.sql.BasicColumn;
import org.mybatis.dynamic.sql.SqlBuilder;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlTable;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
import org.mybatis.dynamic.sql.select.SelectModel;
import org.mybatis.dynamic.sql.select.join.EqualTo;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author 云筑产品开发平台组
 * @version V3.2
 * @copyright 深圳市乐程软件有限公司（http://www.szlecheng.cn）
 * @date 2024/10/26
 */
@Service
public class VisualDevInfoServiceImpl implements VisualDevInfoService {

    @Autowired
    private DbLinkService dblinkService;
    @Autowired
    private FlowFormDataMapper flowFormDataMapper;
    @Autowired
    private OnlineSwapDataUtils onlineSwapDataUtils;
    @Autowired
    private FlowFormDataUtil flowDataUtil;

    @Override
    public VisualdevModelDataInfoVO getEditDataInfo(String id, VisualdevEntity visualdevEntity, OnlineInfoModel model) {
        VisualdevModelDataInfoVO vo = new VisualdevModelDataInfoVO();
        Map<String, Object> editDataInfo = flowDataUtil.getEditDataInfo(visualdevEntity, id, model);
        if (editDataInfo != null && editDataInfo.size() > 0) {
            vo.setId(editDataInfo.get(FlowFormConstant.ID));
            vo.setData(JsonUtilEx.getObjectToString(editDataInfo));
        }
        return vo;
    }

    @Override
    public VisualdevModelDataInfoVO getDetailsDataInfo(String id, VisualdevEntity visualdevEntity) {
        return this.getDetailsDataInfo(id, visualdevEntity,
                OnlineInfoModel.builder().needRlationFiled(true).needSwap(true).build());
    }

    @Override
    public VisualdevModelDataInfoVO getDetailsDataInfo(String id, VisualdevEntity visualdevEntity,
            OnlineInfoModel infoModel) {
        VisualdevModelDataInfoVO vo = new VisualdevModelDataInfoVO();
        Map<String, Object> allDataMap = new HashMap<>();
        Map<String, Object> allDataResMap = new HashMap<>();
        FormDataModel formData = JsonUtil.getJsonToBean(visualdevEntity.getFormData(), FormDataModel.class);
        Boolean logicalDelete = formData.getLogicalDelete();
        // 权限参数
        ColumnDataModel columnDataModel = JsonUtil.getJsonToBean(visualdevEntity.getColumnData(),
                ColumnDataModel.class);
        Boolean needP = false;
        List<String> formPerList = new ArrayList<>();
        if (columnDataModel != null && StringUtil.isNotEmpty(infoModel.getMenuId())) {
            needP = columnDataModel.getUseFormPermission();
            Map<String, Object> pMap = PermissionInterfaceImpl.getFormMap();
            if (pMap.get(infoModel.getMenuId()) != null) {
                formPerList = JsonUtil.getJsonToList(pMap.get(infoModel.getMenuId()), ModuleFormModel.class).stream()
                        .map(ModuleFormModel::getEnCode).collect(Collectors.toList());
            }
        }

        List<FieLdsModel> list = JsonUtil.getJsonToList(formData.getFields(), FieLdsModel.class);
        List<TableModel> tableModelList = JsonUtil.getJsonToList(visualdevEntity.getVisualTables(), TableModel.class);
        List<FormAllModel> formAllModel = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(infoModel.getFormAllModel())) {
            formAllModel = infoModel.getFormAllModel();
        } else {
            RecursionForm recursionForm = new RecursionForm(list, tableModelList);
            FormCloumnUtil.recursionForm(recursionForm, formAllModel);
        }
        // form的属性
        List<FormAllModel> mast = formAllModel.stream()
                .filter(t -> FormEnum.mast.getMessage().equals(t.getYunzhupaasKey())).collect(Collectors.toList());
        List<FormAllModel> table = formAllModel.stream()
                .filter(t -> FormEnum.table.getMessage().equals(t.getYunzhupaasKey())).collect(Collectors.toList());
        List<FormAllModel> mastTable = formAllModel.stream()
                .filter(t -> FormEnum.mastTable.getMessage().equals(t.getYunzhupaasKey())).collect(Collectors.toList());

        List<String> relationFiled = new ArrayList() {
            {
                add(YunzhupaasKeyConsts.RELATIONFORM);
                add(YunzhupaasKeyConsts.RELATIONFORM_ATTR);
            }
        };

        TableModel mainTable = tableModelList.stream().filter(t -> t.getTypeId().equals("1")).findFirst().orElse(null);

        DbLinkEntity linkEntity = "0".equals(visualdevEntity.getDbLinkId()) ? null
                : dblinkService.getInfo(visualdevEntity.getDbLinkId());
        try {
            DynamicDataSourceUtil.switchToDataSource(linkEntity);
            @Cleanup
            Connection conn = ConnUtil.getConnOrDefault(linkEntity);
            String databaseProductName = conn.getMetaData().getDatabaseProductName();
            String dbType = conn.getMetaData().getDatabaseProductName().trim();
            boolean toUpperCase = databaseProductName.equalsIgnoreCase("oracle")
                    || databaseProductName.equalsIgnoreCase("DM DBMS");
            // 获取主键
            TableFields tableFields = mainTable.getFields().stream().filter(t -> Objects.equals(t.getPrimaryKey(), 1)
                    && !t.getField().toLowerCase().contains(TableFeildsEnum.TENANTID.getField())).findFirst()
                    .orElse(null);
            String pKeyName = Objects.nonNull(tableFields) ? tableFields.getField()
                    : toUpperCase ? TableFeildsEnum.FID.getField().toUpperCase() : TableFeildsEnum.FID.getField();
            SqlTable mainSqlTable = SqlTable.of(mainTable.getTable());
            // 查询主表数据
            Map<String, Object> mainAllMap = searchMainData(id, infoModel, mainTable, tableModelList);
            if (mainAllMap.size() == 0) {
                return vo;
            }
            // 是否去除关联表单及关联表单字段
            if (!infoModel.isNeedRlationFiled()) {
                mast = mast.stream()
                        .filter(t -> !relationFiled
                                .contains(t.getFormColumnModel().getFieLdsModel().getConfig().getYunzhupaasKey()))
                        .collect(Collectors.toList());
            }
            // 主表
            List<String> mainTableFields = mast.stream()
                    .filter(m -> StringUtil.isNotEmpty(m.getFormColumnModel().getFieLdsModel().getVModel()))
                    .map(s -> s.getFormColumnModel().getFieLdsModel().getVModel()).collect(Collectors.toList());
            // 开启权限移除字段
            if (needP) {
                if (CollectionUtils.isEmpty(formPerList)) {
                    mainTableFields = Collections.EMPTY_LIST;
                } else {
                    List<String> newList = new ArrayList<>();
                    for (String item : mainTableFields) {
                        if (formPerList.contains(item)) {
                            newList.add(item);
                        }
                    }
                    mainTableFields = newList;
                }
            }
            List<BasicColumn> mainTableBasicColumn = mainTableFields.stream()
                    .map(m -> SqlTable.of(mainTable.getTable()).column(m)).collect(Collectors.toList());
            // 无字段时查询主键
            mainTableBasicColumn.add(SqlTable.of(mainTable.getTable()).column(pKeyName));

            SelectStatementProvider mainRender = SqlBuilder.select(mainTableBasicColumn).from(mainSqlTable)
                    .where(mainSqlTable.column(pKeyName),
                            SqlBuilder.isEqualTo(mainAllMap.get(pKeyName)))
                    .build().render(RenderingStrategies.MYBATIS3);
            List<Map<String, Object>> mapList = flowFormDataMapper.selectManyMappedRows(mainRender);

            if (ObjectUtil.isNotEmpty(mapList) && mapList.size() > 0) {
                allDataMap.putAll(mapList.get(0));
            }

            // 列表子表
            Map<String, List<FormMastTableModel>> groupByTableNames = mastTable.stream()
                    .map(mt -> mt.getFormMastTableModel()).collect(Collectors.groupingBy(ma -> ma.getTable()));
            Iterator<Map.Entry<String, List<FormMastTableModel>>> entryIterator = groupByTableNames.entrySet()
                    .iterator();
            while (entryIterator.hasNext()) {
                Map.Entry<String, List<FormMastTableModel>> next = entryIterator.next();
                String childTableName = next.getKey();
                List<FormMastTableModel> childMastTableList = next.getValue();
                // 是否去除关联表单及关联表单字段
                if (!infoModel.isNeedRlationFiled()) {
                    childMastTableList = childMastTableList.stream()
                            .filter(t -> !relationFiled
                                    .contains(t.getMastTable().getFieLdsModel().getConfig().getYunzhupaasKey()))
                            .collect(Collectors.toList());
                }
                // 开启权限移除字段
                if (needP) {
                    if (CollectionUtils.isEmpty(formPerList)) {
                        childMastTableList = Collections.EMPTY_LIST;
                    } else {
                        List<FormMastTableModel> newList = new ArrayList<>();
                        for (FormMastTableModel item : childMastTableList) {
                            if (formPerList.contains(item.getVModel())) {
                                newList.add(item);
                            }
                        }
                        childMastTableList = newList;
                    }
                }
                TableModel childTableModel = tableModelList.stream().filter(t -> t.getTable().equals(childTableName))
                        .findFirst().orElse(null);
                SqlTable mastSqlTable = SqlTable.of(childTableName);
                List<BasicColumn> mastTableBasicColumn = childMastTableList.stream()
                        .filter(m -> StringUtil.isNotEmpty(m.getField()))
                        .map(m -> mastSqlTable.column(m.getField())).collect(Collectors.toList());
                // 添加副表关联字段，不然数据会空没有字段名称
                mastTableBasicColumn.add(mastSqlTable.column(childTableModel.getTableField()));

                // 主表主键
                String mainField = childTableModel.getRelationField();
                Object mainValue = new CaseInsensitiveMap(mainAllMap).get(mainField);
                // 子表外键
                String childFoIdFiled = childTableModel.getTableField();
                // 外键字段是否varchar转换
                TableFields fogIdField = childTableModel.getFields().stream()
                        .filter(t -> t.getField().equals(childFoIdFiled)).findFirst().orElse(null);
                boolean fogIdTypeString = Objects.nonNull(fogIdField)
                        ? fogIdField.getDataType().toLowerCase().contains("varchar")
                        : false;
                if (fogIdTypeString) {
                    mainValue = mainValue.toString();
                }

                SelectStatementProvider mastRender = SqlBuilder.select(mastTableBasicColumn).from(mastSqlTable)
                        .where(mastSqlTable.column(childFoIdFiled),
                                SqlBuilder.isEqualTo(mainValue))
                        .build().render(RenderingStrategies.MYBATIS3);
                List<Map<String, Object>> childMapList = flowFormDataMapper.selectManyMappedRows(mastRender);
                if (CollectionUtils.isNotEmpty(childMapList)) {
                    Map<String, Object> soloDataMap = childMapList.get(0);
                    Map<String, Object> renameKeyMap = new HashMap<>();
                    for (Map.Entry entry : soloDataMap.entrySet()) {
                        FormMastTableModel model = childMastTableList.stream()
                                .filter(child -> child.getField().equalsIgnoreCase(String.valueOf(entry.getKey())))
                                .findFirst().orElse(null);
                        if (model != null) {
                            renameKeyMap.put(model.getVModel(), entry.getValue());
                        }
                    }
                    List<Map<String, Object>> mapList1 = new ArrayList<>();
                    mapList1.add(renameKeyMap);
                    allDataMap.putAll(mapList1.get(0));
                }
            }

            // 设计子表
            Boolean finalNeedP = needP;
            List<String> finalFormPerList = formPerList;
            table.stream().map(t -> t.getChildList()).forEach(
                    t1 -> {
                        String childTableName = t1.getTableName();
                        TableModel tableModel = tableModelList.stream()
                                .filter(tm -> tm.getTable().equals(childTableName)).findFirst().orElse(null);
                        SqlTable childSqlTable = SqlTable.of(childTableName);
                        List<FormColumnModel> chilFieldList = t1.getChildList().stream()
                                .filter(t2 -> StringUtil.isNotEmpty(t2.getFieLdsModel().getVModel()))
                                .collect(Collectors.toList());
                        String tableModelName = t1.getTableModel();
                        // 开启权限移除字段
                        if (finalNeedP) {
                            if (CollectionUtils.isEmpty(finalFormPerList)) {
                                chilFieldList = Collections.EMPTY_LIST;
                            } else {
                                List<FormColumnModel> newList = new ArrayList<>();
                                for (FormColumnModel item : chilFieldList) {
                                    if (finalFormPerList
                                            .contains(tableModelName + "-" + item.getFieLdsModel().getVModel())) {
                                        newList.add(item);
                                    }
                                }
                                chilFieldList = newList;
                            }
                        }
                        List<BasicColumn> childFields = chilFieldList.stream()
                                .map(t2 -> childSqlTable.column(t2.getFieLdsModel().getVModel()))
                                .collect(Collectors.toList());

                        childFields.add(childSqlTable.column(tableModel.getTableField()));
                        String childKeyName = flowDataUtil.getKey(tableModel, dbType);
                        childFields.add(childSqlTable.column(childKeyName));
                        // 主表主键
                        String mainField = tableModel.getRelationField();
                        Object mainValue = new CaseInsensitiveMap(mainAllMap).get(mainField);
                        // 子表外键
                        String childFoIdFiled = tableModel.getTableField();
                        // 外键字段是否varchar转换
                        TableFields fogIdField = tableModel.getFields().stream()
                                .filter(t -> t.getField().equals(childFoIdFiled)).findFirst().orElse(null);
                        boolean fogIdTypeString = Objects.nonNull(fogIdField)
                                ? fogIdField.getDataType().toLowerCase().contains("varchar")
                                : false;
                        if (fogIdTypeString) {
                            mainValue = mainValue.toString();
                        }

                        // todo
                        QueryExpressionDSL<SelectModel>.QueryExpressionWhereBuilder childWhere = SqlBuilder
                                .select(childFields).from(childSqlTable).where();
                        childWhere.and(childSqlTable.column(tableModel.getTableField()),
                                SqlBuilder.isEqualTo(mainValue));
                        // 逻辑删除不展示
                        if (logicalDelete) {
                            childWhere.and(childSqlTable.column(TableFeildsEnum.DELETEMARK.getField()),
                                    SqlBuilder.isNull());
                        }
                        SelectStatementProvider childRender = childWhere.build().render(RenderingStrategies.MYBATIS3);
                        List<Map<String, Object>> childMapList = flowFormDataMapper.selectManyMappedRows(childRender);
                        if (ObjectUtil.isNotEmpty(childMapList)) {
                            Map<String, Object> childMap = new HashMap<>(1);
                            childMap.put(t1.getTableModel(), childMapList);
                            allDataMap.putAll(childMap);
                        }
                    });
            // 数据转换
            List<FieLdsModel> fields = new ArrayList<>();
            OnlinePublicUtils.recursionFields(fields, list);

            // 添加id属性
            List<Map<String, Object>> dataList = FormPublicUtils.addIdToList(new ArrayList() {
                {
                    add(allDataMap);
                }
            }, pKeyName);
            // 详情没有区分行内编辑
            if (infoModel.isNeedSwap()) {
                allDataResMap = (Map<String, Object>) onlineSwapDataUtils
                        .getSwapInfo(dataList, fields, visualdevEntity.getId(), false, null).get(0);
            } else {
                allDataResMap = allDataMap;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            DynamicDataSourceUtil.clearSwitchDataSource();
        }
        vo.setId(allDataResMap.get(FlowFormConstant.ID));
        vo.setData(JsonUtilEx.getObjectToString(allDataResMap));
        return vo;
    }

    /**
     * 根据指定字段查询主表数据
     *
     * @param id
     * @param model
     * @param mainTable
     * @param tableModelList
     * @return
     */
    private Map<String, Object> searchMainData(String id, OnlineInfoModel model, TableModel mainTable,
            List<TableModel> tableModelList) {
        SqlTable mainSqlTable = SqlTable.of(mainTable.getTable());
        TableFields mainKeyModel = mainTable.getFields().stream().filter(t -> Objects.equals(t.getPrimaryKey(), 1)
                && !t.getField().toLowerCase().contains(TableFeildsEnum.TENANTID.getField())).findFirst().orElse(null);
        String propsValue = model.getPropsValue();
        SqlColumn column = null;
        TableFields storedFieldModel = null;
        if (StringUtil.isNotEmpty(propsValue)) {
            if (propsValue.contains("_yunzhupaas_")) {
                String[] split = propsValue.split("_yunzhupaas_");
                String thisTable = split[0].substring(5);
                String thisField = split[1];
                TableModel thisTableModel = tableModelList.stream()
                        .filter(t -> t.getTable().equalsIgnoreCase(thisTable)).findFirst().orElse(null);
                storedFieldModel = thisTableModel.getFields().stream()
                        .filter(t -> t.getField().equalsIgnoreCase(thisField)).findFirst().orElse(null);
                SqlTable sqlTable = SqlTable.of(split[0].substring(5));
                column = sqlTable.column(storedFieldModel.getField());
            } else {

                storedFieldModel = mainTable.getFields().stream().filter(t -> t.getField().equalsIgnoreCase(propsValue))
                        .findFirst().orElse(null);
                column = mainSqlTable.column(storedFieldModel.getField());
            }
        } else {
            storedFieldModel = mainKeyModel;
            column = mainSqlTable.column(storedFieldModel.getField());
        }
        // 查询的字段-字段类型转换
        Object idObj = id;
        if (VisualConst.DB_INT_ALL.contains(storedFieldModel.getDataType().toLowerCase())) {
            idObj = Long.parseLong(id);
        }

        QueryExpressionDSL<SelectModel> from = SqlBuilder.select(mainSqlTable.allColumns()).from(mainSqlTable);
        for (TableModel item : tableModelList) {
            if (!Objects.equals("1", item.getTypeId())) {
                SqlTable sqlTable = SqlTable.of(item.getTable());
                String tableField = item.getTableField();
                String relationField = item.getRelationField();
                from.leftJoin(sqlTable).on(sqlTable.column(tableField),
                        new EqualTo(mainSqlTable.column(relationField)));
            }
        }
        QueryExpressionDSL<SelectModel>.QueryExpressionWhereBuilder where = from.where(column,
                SqlBuilder.isEqualTo(idObj));
        SelectStatementProvider render = where.build().render(RenderingStrategies.MYBATIS3);
        List<Map<String, Object>> maps = flowFormDataMapper.selectManyMappedRows(render);
        if (CollectionUtils.isNotEmpty(maps)) {
            return maps.get(0);
        }
        return new HashMap<>();
    }
}
