package com.yunzhupaas.onlinedev.service.impl;

import cn.hutool.core.bean.BeanUtil;
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.yunzhupaas.base.entity.VisualdevReleaseEntity;
import com.yunzhupaas.base.model.VisualLogModel;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.yunzhupaas.base.service.VisualdevReleaseService;
import com.yunzhupaas.constant.YunzhupaasConst;
import com.yunzhupaas.event.ProjectEventListener;
import com.yunzhupaas.model.visualJson.FieLdsModel;
import com.yunzhupaas.model.visualJson.FormDataModel;
import com.yunzhupaas.model.visualJson.TableFields;
import com.yunzhupaas.model.visualJson.TableModel;
import com.yunzhupaas.model.visualJson.config.ConfigModel;
import com.yunzhupaas.module.ProjectEventBuilder;
import com.yunzhupaas.module.ProjectEventInstance;
import com.yunzhupaas.onlinedev.entity.VisualLogEntity;
import com.yunzhupaas.onlinedev.mapper.VisualLogMapper;
import com.yunzhupaas.onlinedev.model.OnlineDevEnum.OnlineDataTypeEnum;
import com.yunzhupaas.onlinedev.model.log.VisualLogForm;
import com.yunzhupaas.onlinedev.model.log.VisualLogPage;
import com.yunzhupaas.onlinedev.service.VisualLogService;
import com.yunzhupaas.onlinedev.util.onlineDevUtil.OnlinePublicUtils;
import com.yunzhupaas.onlinedev.util.onlineDevUtil.OnlineSwapDataUtils;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.PublishEventUtil;
import com.yunzhupaas.util.TableFeildsEnum;
import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 数据日志实现
 *
 * @author 云筑产品开发平台组
 * @version v5.1.0
 * @copyright 深圳市乐程软件有限公司
 * @date 2024/8/27 18:24:42
 */
@Service
public class VisualLogServiceImpl extends SuperServiceImpl<VisualLogMapper, VisualLogEntity>
        implements VisualLogService {
    @Autowired
    private VisualdevReleaseService visualdevReleaseService;
    @Autowired
    private OnlineSwapDataUtils onlineSwapDataUtils;

    /**
     * 创建日志事件
     *
     * @param form 数据id
     */
    @Override
    public void createEventLog(VisualLogForm form) {
        PublishEventUtil.publishLocalEvent(new ProjectEventBuilder(YunzhupaasConst.VSLOG_EVENT_KEY, form));
    }

    @Override
    public List<VisualLogEntity> getLogList(VisualLogPage pagination) {
        QueryWrapper<VisualLogEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(VisualLogEntity::getModelId, pagination.getModelId());
        queryWrapper.lambda().eq(VisualLogEntity::getDataId, pagination.getDataId());
        // 排序
        queryWrapper.lambda().orderByDesc(VisualLogEntity::getCreatorTime);
        Page<VisualLogEntity> page = new Page<>(pagination.getCurrentPage(), pagination.getPageSize());
        IPage<VisualLogEntity> iPage = this.page(page, queryWrapper);
        return pagination.setData(iPage.getRecords(), iPage.getTotal());
    }

    /**
     * 监听日志插入
     *
     * @param redisEvent
     */
    @ProjectEventListener(channelRegex = YunzhupaasConst.VSLOG_EVENT_KEY + ".*")
    public void createLogByEvent(ProjectEventInstance redisEvent) {
        VisualLogForm form = (VisualLogForm) redisEvent.getSource();
        VisualLogEntity visualLogEntity = new VisualLogEntity();
        visualLogEntity.setType(form.getType());
        visualLogEntity.setModelId(form.getModelId());
        visualLogEntity.setDataId(form.getDataId());

        // 修改数据
        if (Objects.equals(form.getType(), 1)) {
            List<VisualLogModel> listLog = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(form.getListLog())) {
                listLog = form.getListLog();
            } else {
                addLog(form, listLog);
            }
            visualLogEntity.setDataLog(JsonUtil.getObjectToString(listLog));
            if (CollectionUtils.isNotEmpty(listLog)) {
                this.save(visualLogEntity);
            }
        } else {
            // 新增数据
            this.save(visualLogEntity);
        }
    }

    public void addLog(VisualLogForm formSource, List<VisualLogModel> listLog) {
        VisualLogForm form = BeanUtil.copyProperties(formSource, VisualLogForm.class);
        VisualdevReleaseEntity visualdevEntity = visualdevReleaseService.getById(form.getModelId());
        FormDataModel formData = JsonUtil.getJsonToBean(visualdevEntity.getFormData(), FormDataModel.class);
        List<FieLdsModel> fieLdsModels = JsonUtil.getJsonToList(formData.getFields(), FieLdsModel.class);
        List<TableModel> tableModels = JsonUtil.getJsonToList(visualdevEntity.getVisualTables(), TableModel.class);

        List<FieLdsModel> fields = new ArrayList<>();
        OnlinePublicUtils.recursionFields(fields, fieLdsModels);

        List<Map<String, Object>> swapInfoOld = onlineSwapDataUtils.getSwapInfo(new ArrayList<Map<String, Object>>() {
            {
                add(form.getOldData());
            }
        }, fields, visualdevEntity.getId(), false, null);
        Map<String, Object> oldData = swapInfoOld.get(0);
        List<Map<String, Object>> swapInfoNew = onlineSwapDataUtils.getSwapInfo(new ArrayList<Map<String, Object>>() {
            {
                add(form.getNewData());
            }
        }, fields, visualdevEntity.getId(), false, null);
        Map<String, Object> newData = swapInfoNew.get(0);

        for (FieLdsModel item : fields) {
            ConfigModel config = item.getConfig();
            String yunzhupaasKey = config.getYunzhupaasKey();
            String label = config.getLabel();
            String dataType = config.getDataType();
            // 移除系统字段
            if (isSkipFields(item))
                continue;
            if (YunzhupaasKeyConsts.CHILD_TABLE.equals(yunzhupaasKey)) {
                TableModel tableModel = tableModels.stream().filter(t -> t.getTable().equals(config.getTableName()))
                        .findFirst().orElse(null);
                TableFields mainField = tableModel.getFields().stream()
                        .filter(t -> Objects.equals(t.getPrimaryKey(), 1)
                                && !t.getField().equalsIgnoreCase(TableFeildsEnum.TENANTID.getField()))
                        .findFirst().orElse(null);
                String mainKey = mainField.getField();

                List<FieLdsModel> children = item.getConfig().getChildren();
                String vModel = item.getVModel();
                // 子表数据
                List<Map<String, Object>> childData = new ArrayList<>();
                // 子表表头
                List<Map<String, Object>> childField = new ArrayList<>();
                for (FieLdsModel childItem : children) {
                    String yunzhupaasKeyChild = childItem.getConfig().getYunzhupaasKey();
                    if (isSkipFields(childItem))
                        continue;
                    Map<String, Object> childItemMap = new HashMap<>();
                    childItemMap.put("prop", childItem.getVModel());
                    childItemMap.put("label", childItem.getConfig().getLabel());
                    childItemMap.put("yunzhupaasKey", yunzhupaasKeyChild);
                    boolean nameModified = false;
                    if (YunzhupaasKeyConsts.getNameModified().contains(yunzhupaasKeyChild)) {
                        if (YunzhupaasKeyConsts.getNameModifiedNotDynamic().contains(yunzhupaasKeyChild)
                                || OnlineDataTypeEnum.DYNAMIC.getType().equals(childItem.getConfig().getDataType())) {
                            nameModified = true;
                        }
                    }
                    childItemMap.put("nameModified", nameModified);
                    childField.add(childItemMap);
                }

                List<Map<String, Object>> childOld = oldData.get(vModel) == null ? new ArrayList<>()
                        : (List) oldData.get(vModel);
                List<Map<String, Object>> childNew = newData.get(vModel) == null ? new ArrayList<>()
                        : (List) newData.get(vModel);
                List<Object> newIds = childNew.stream().map(t -> t.get(mainKey)).collect(Collectors.toList());
                List<Map<String, Object>> deleteMap = childOld.stream().filter(t -> !newIds.contains(t.get(mainKey)))
                        .collect(Collectors.toList());
                for (Map<String, Object> chilMap : deleteMap) {
                    Map<String, Object> childDataMap = new HashMap<>();
                    for (FieLdsModel childItem : children) {
                        String childYunzhupaasKey = childItem.getConfig().getYunzhupaasKey();
                        // 移除系统字段
                        if (isSkipFields(childItem))
                            continue;
                        String childVmodel = childItem.getVModel();
                        String childVmodel_old = "yunzhupaas_old_" + childItem.getVModel();
                        String oldValue = getValueByType(chilMap, childVmodel, childYunzhupaasKey);
                        childDataMap.put(childVmodel, null);
                        childDataMap.put(childVmodel_old, oldValue);
                        childDataMap.put("yunzhupaas_type", 2);
                    }
                    childData.add(childDataMap);
                }
                for (Map<String, Object> chilMap : childNew) {
                    Object mainId = chilMap.get(mainKey);
                    Map<String, Object> oldMap = childOld.stream().filter(t -> t.get(mainKey).equals(mainId))
                            .findFirst().orElse(null);
                    Integer yunzhupaas_type = 1;
                    if (oldMap == null) {
                        yunzhupaas_type = 0;
                    }
                    Map<String, Object> childDataMap = new HashMap<>();
                    boolean hasChanged = false;
                    for (FieLdsModel childItem : children) {
                        String childYunzhupaasKey = childItem.getConfig().getYunzhupaasKey();
                        // 移除系统字段
                        if (isSkipFields(childItem))
                            continue;
                        String childVmodel = childItem.getVModel();
                        String childVmodel_old = "yunzhupaas_old_" + childItem.getVModel();
                        String newValue = getValueByType(chilMap, childVmodel, childYunzhupaasKey);
                        String oldValue = getValueByType(oldMap, childVmodel, childYunzhupaasKey);
                        if (!Objects.equals(newValue, oldValue)) {
                            hasChanged = true;
                        }
                        childDataMap.put(childVmodel, newValue);
                        childDataMap.put(childVmodel_old, oldValue);
                        childDataMap.put("yunzhupaas_type", yunzhupaas_type);
                    }
                    if (hasChanged) {
                        childData.add(childDataMap);
                    }
                }
                if (CollectionUtils.isNotEmpty(childData)) {
                    VisualLogModel vlogModel = new VisualLogModel();
                    vlogModel.setField(vModel);
                    vlogModel.setFieldName(label);
                    vlogModel.setYunzhupaasKey(yunzhupaasKey);
                    vlogModel.setChidData(childData);
                    vlogModel.setChidField(childField);
                    vlogModel.setType(1);
                    listLog.add(vlogModel);
                }
            } else {
                String vModel = item.getVModel();
                if (!Objects.equals(oldData.get(vModel), newData.get(vModel))) {
                    Integer actionType = 1;// 0-新增，1-修改
                    if (oldData.get(vModel) == null || oldData.get(vModel).toString().trim().isEmpty()) {
                        actionType = 0;
                    }
                    boolean nameModified = false;
                    if (YunzhupaasKeyConsts.getNameModified().contains(yunzhupaasKey)) {
                        if (YunzhupaasKeyConsts.getNameModifiedNotDynamic().contains(yunzhupaasKey)
                                || OnlineDataTypeEnum.DYNAMIC.getType().equals(dataType)) {
                            nameModified = true;
                        }
                    }

                    String newValue = getValueByType(newData, vModel, yunzhupaasKey);
                    String oldValue = getValueByType(oldData, vModel, yunzhupaasKey);
                    VisualLogModel vlogModel = new VisualLogModel();
                    vlogModel.setField(vModel);
                    vlogModel.setFieldName(label);
                    vlogModel.setYunzhupaasKey(yunzhupaasKey);
                    vlogModel.setNewData(newValue);
                    vlogModel.setOldData(oldValue);
                    vlogModel.setType(actionType);
                    vlogModel.setNameModified(nameModified);
                    listLog.add(vlogModel);
                }
            }
        }
    }

    /**
     * 跳过字段不处理
     *
     * @param childItem
     * @return
     */
    private boolean isSkipFields(FieLdsModel childItem) {
        // 字段不处理直接跳过 ：（YunzhupaasKeyConsts.CALCULATE 计算公式仅展示也跳过）
        List<String> skipFields = new ArrayList<>();
        skipFields.addAll(YunzhupaasKeyConsts.getSystemKey());
        skipFields.add(YunzhupaasKeyConsts.POPUPSELECT_ATTR);
        skipFields.add(YunzhupaasKeyConsts.RELATIONFORM_ATTR);
        String yunzhupaasKey = childItem.getConfig().getYunzhupaasKey();
        return skipFields.contains(yunzhupaasKey)
                || (YunzhupaasKeyConsts.CALCULATE.equals(yunzhupaasKey) && Objects.equals(childItem.getIsStorage(), 0));
    }

    private String getValueByType(Map<String, Object> map, String vModel, String yunzhupaasKey) {
        if (map != null) {
            Object o = map.get(vModel);
            String value = o == null ? "" : o.toString();
            switch (yunzhupaasKey) {
                case YunzhupaasKeyConsts.UPLOADFZ:
                    List<Map<String, String>> listM = (List) o;
                    if (listM != null) {
                        StringJoiner sj = new StringJoiner(",");
                        listM.stream().forEach(t -> sj.add(t.get("name").toString()));
                        value = sj.toString();
                    }
                    break;
                case YunzhupaasKeyConsts.LOCATION:
                    Map<String, Object> lcationMap = JsonUtil.stringToMap(value);
                    if (MapUtils.isNotEmpty(lcationMap)) {
                        value = lcationMap.get("fullAddress") != null ? lcationMap.get("fullAddress").toString() : "";
                    }
                    break;
                default:
                    break;
            }
            return value;
        }
        return null;
    }
}
