package com.yeejoin.equipmanage.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.yeejoin.equipmanage.common.entity.DynamicFormColumn;
import com.yeejoin.equipmanage.common.entity.DynamicFormGroup;
import com.yeejoin.equipmanage.common.entity.DynamicFormInstance;
import com.yeejoin.equipmanage.common.entity.publics.BaseEntity;
import com.yeejoin.equipmanage.common.exception.BaseException;
import com.yeejoin.equipmanage.common.utils.CodeGenerate;
import com.yeejoin.equipmanage.common.utils.StringUtil;
import com.yeejoin.equipmanage.common.vo.DynamicFormGroupVo;
import com.yeejoin.equipmanage.service.IDynamicFormColumnService;
import com.yeejoin.equipmanage.service.IDynamicFormGroupService;
import com.yeejoin.equipmanage.service.IDynamicFormInstanceService;
import com.yeejoin.equipmanage.service.IDynamicFormService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;

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

/**
 * @author DELL
 */
@Service
public class DynamicFormServiceImpl implements IDynamicFormService {

    @Autowired
    Sequence sequence;

    @Autowired
    IDynamicFormGroupService iDynamicFormGroupService;

    @Autowired
    IDynamicFormColumnService iDynamicFormColumnService;

    @Autowired
    IDynamicFormInstanceService iDynamicFormInstanceService;

    @Override
    public Object nextIdCode() {
        Map<String, Object> param = new HashMap<>(2);
        param.put("id", sequence.nextId());
        param.put("code", CodeGenerate.generateUUID());
        return param;
    }

    @Override
    public DynamicFormGroup getGroupsAndColumns(Long groupId) {
        //0.前置校验
        DynamicFormGroup dynamicFormGroup = iDynamicFormGroupService.getById(groupId);
        if (dynamicFormGroup == null) {
            throw new BaseException("分组信息不存在");
        }
        //1.组织树
        this.stringToJsonGroupConfig(dynamicFormGroup);
        buildGroupTreeWithColumn(dynamicFormGroup);
        return dynamicFormGroup;
    }

    private void stringToJsonGroupConfig(DynamicFormGroup dynamicFormGroup) {
        JSONObject jsonObject = new JSONObject();
        if (dynamicFormGroup.getGroupConfig() != null) {
            jsonObject = JSONObject.parseObject(dynamicFormGroup.getGroupConfig().toString());
        }
        dynamicFormGroup.setGroupConfig(jsonObject);
    }

    @Override
    public DynamicFormGroup saveGroupAndColumn(DynamicFormGroup dynamicFormGroup, String orgCode) {
        //1.树转行
        List<DynamicFormGroup> groupList = dynamicFormGroup.getChildren();
        List<DynamicFormGroup> formGroups = new ArrayList<>();
        List<DynamicFormColumn> formColumns = new ArrayList<>();
        this.transferTreeToList(formGroups, formColumns, groupList);
        //2.数据分组进行删除或者保存
        Map<Boolean, List<DynamicFormGroup>> formGroupMap = formGroups.stream().collect(Collectors.groupingBy(DynamicFormGroup::getIsDelete, Collectors.mapping(g -> {
            g.setCreateDate(new Date());
            g.setOrgCode(orgCode);
            g.setCreatorId(RequestContext.getExeUserId() != null ? Long.parseLong(RequestContext.getExeUserId()) : null);
            return g;
        }, Collectors.toList())));
        //2.1需要保存的分组数据
        List<DynamicFormGroup> saveGroups = formGroupMap.get(false);
        if (saveGroups != null && !saveGroups.isEmpty()) {
            iDynamicFormGroupService.saveOrUpdateBatch(saveGroups);
        }
        //2.2需要删除的分组数据
        List<DynamicFormGroup> deleteGroups = formGroupMap.get(true);
        if (deleteGroups != null && !deleteGroups.isEmpty()) {
            iDynamicFormGroupService.removeByIds(deleteGroups.stream().map(BaseEntity::getId).collect(Collectors.toList()));
        }
        //3.字段的删除或者保存
        Map<Boolean, List<DynamicFormColumn>> formColumnMap = formColumns.stream().collect(Collectors.groupingBy(DynamicFormColumn::getIsDelete, Collectors.mapping(g -> {
            g.setCreateDate(new Date());
            g.setCreatorId(RequestContext.getExeUserId() != null ? Long.parseLong(RequestContext.getExeUserId()) : null);
            return g;
        }, Collectors.toList())));
        //3.1保存的字段数据
        List<DynamicFormColumn> saveFormColumns = formColumnMap.get(false);
        if (saveFormColumns != null && !saveFormColumns.isEmpty()) {
            iDynamicFormColumnService.saveOrUpdateBatch(saveFormColumns);
        }
        //3.2删除的字段数据
        List<DynamicFormColumn> deleteFormColumns = formColumnMap.get(true);
        if (deleteFormColumns != null && !deleteFormColumns.isEmpty()) {
            iDynamicFormColumnService.removeByIds(deleteFormColumns.stream().map(BaseEntity::getId).collect(Collectors.toList()));
        }
        return this.getGroupsAndColumns(dynamicFormGroup.getId());
    }

    @Override
    public Object getInstanceDetail(String instanceId, Long groupId) {
        //1.查询实例信息
        List<DynamicFormInstance> dynamicFormInstances = new ArrayList<>();
        if (StringUtil.isNotEmpty(instanceId)) {
            dynamicFormInstances = iDynamicFormInstanceService.list(new QueryWrapper<DynamicFormInstance>().lambda().eq(DynamicFormInstance::getInstanceId, instanceId));
        }
        //2.组织树数据，wl_dynamic_form_group 树结构，填充字段及字段对应value
        return this.getGroupsAndColumnsWithValue(groupId, dynamicFormInstances);
    }

    private DynamicFormGroupVo getGroupsAndColumnsWithValue(Long groupId, List<DynamicFormInstance> dynamicFormInstances) {
        DynamicFormGroup dynamicFormGroup = iDynamicFormGroupService.getById(groupId);
        if (dynamicFormGroup == null) {
            throw new BaseException("分组信息不存在");
        }//0.对象转换
        DynamicFormGroupVo groupVo = new DynamicFormGroupVo();
        Bean.copyExistPropertis(dynamicFormGroup, groupVo);
        groupVo.setGroupConfig(dynamicFormGroup.getGroupConfig() != null ? dynamicFormGroup.getGroupConfig() : new JSONObject());
        //1.组织树
        buildGroupsAndColumnsTreeWithValue(groupVo, dynamicFormInstances);
        return groupVo;
    }

    private void buildGroupsAndColumnsTreeWithValue(DynamicFormGroupVo dynamicFormGroupVo, List<DynamicFormInstance> dynamicFormInstances) {
        //1.list 转Map key为formColumnId，用来填充已经填写的值
        Map<Long, DynamicFormInstance> formInstanceMap = dynamicFormInstances.stream().collect(Collectors.toMap(DynamicFormInstance::getFormColumnId, Function.identity()));
        //2.填充字段数据
        this.fillFormColumnWithFiledValue(dynamicFormGroupVo, formInstanceMap);
        //3.处理子分组数据
        List<DynamicFormGroup> groupList = iDynamicFormGroupService.list(new LambdaQueryWrapper<DynamicFormGroup>()
                .eq(DynamicFormGroup::getParentId, dynamicFormGroupVo.getId()).orderByAsc(DynamicFormGroup::getSort));
        List<DynamicFormGroupVo> formGroupVos = groupList.stream().map(s -> {
            this.stringToJsonGroupConfig(s);
            DynamicFormGroupVo target = new DynamicFormGroupVo();
            Bean.copyExistPropertis(s, target);
            return target;
        }).collect(Collectors.toList());
        formGroupVos.forEach(v -> {
            this.fillFormColumnWithFiledValue(v, formInstanceMap);
            buildGroupsAndColumnsTreeWithValue(v, dynamicFormInstances);
        });
        dynamicFormGroupVo.setChildren(formGroupVos);
    }

    private void fillFormColumnWithFiledValue(DynamicFormGroupVo dynamicFormGroupVo, Map<Long, DynamicFormInstance> formInstanceMap) {
        List<DynamicFormColumn> formColumns = iDynamicFormColumnService.list(new LambdaQueryWrapper<DynamicFormColumn>()
                .eq(DynamicFormColumn::getGroupId, dynamicFormGroupVo.getId()));
        //将行数据转为实例数据，使新增及编辑时，返回前端的数据结构统一
        List<DynamicFormInstance> formInstances = formColumns.stream().map(f -> {
            DynamicFormInstance target = new DynamicFormInstance();
            Bean.copyExistPropertis(f, target);
            target.setId(formInstanceMap.get(f.getId()) != null ? formInstanceMap.get(f.getId()).getId() : null);
            target.setFormColumnId(f.getId());
            target.setFieldValue(formInstanceMap.get(f.getId()) != null ? formInstanceMap.get(f.getId()).getFieldValue() : null);
            target.setInstanceId(formInstanceMap.get(f.getId()) != null ? formInstanceMap.get(f.getId()).getInstanceId() : null);
            return target;
        }).collect(Collectors.toList());
        dynamicFormGroupVo.setFormInstances(formInstances);
    }

    private void transferTreeToList(List<DynamicFormGroup> formGroups, List<DynamicFormColumn> formColumns, List<DynamicFormGroup> groupList) {
        formGroups.addAll(groupList);
        groupList.forEach(g -> {
            formColumns.addAll(g.getFormColumns() != null ? g.getFormColumns() : new ArrayList<>());
            List<DynamicFormGroup> childrenFormGroups = g.getChildren();
            if (childrenFormGroups != null && !childrenFormGroups.isEmpty()) {
                transferTreeToList(formGroups, formColumns, childrenFormGroups);
            }
        });
    }

    private void buildGroupTreeWithColumn(DynamicFormGroup dynamicFormGroup) {
        this.fillFormColumns(dynamicFormGroup);
        List<DynamicFormGroup> groupList = iDynamicFormGroupService.list(new LambdaQueryWrapper<DynamicFormGroup>()
                .eq(DynamicFormGroup::getParentId, dynamicFormGroup.getId()).orderByAsc(DynamicFormGroup::getSort));
        groupList.forEach(g -> {
            this.fillFormColumns(g);
            this.stringToJsonGroupConfig(g);
            buildGroupTreeWithColumn(g);
        });
        dynamicFormGroup.setChildren(groupList);
    }

    private void fillFormColumns(DynamicFormGroup dynamicFormGroup) {
        List<DynamicFormColumn> columnList = iDynamicFormColumnService.list(new LambdaQueryWrapper<DynamicFormColumn>()
                .eq(DynamicFormColumn::getGroupId, dynamicFormGroup.getId()).orderByAsc(DynamicFormColumn::getGroupId));
        dynamicFormGroup.setFormColumns(columnList);
    }

}
