package com.yeejoin.equipmanage.service.impl;


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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import com.yeejoin.equipmanage.common.entity.FormGroup;
import com.yeejoin.equipmanage.common.entity.FormGroupColumn;
import com.yeejoin.equipmanage.common.entity.FormInstance;
import com.yeejoin.equipmanage.common.entity.SourceFile;
import com.yeejoin.equipmanage.common.entity.dto.BuildSearchDTO;
import com.yeejoin.equipmanage.common.entity.vo.BuildingVideoListVO;
import com.yeejoin.equipmanage.common.enums.GroupCodeEnum;
import com.yeejoin.equipmanage.common.enums.GroupColumnDataType;
import com.yeejoin.equipmanage.common.utils.RandomUtil;
import com.yeejoin.equipmanage.common.vo.AreaTreeVo;
import com.yeejoin.equipmanage.common.vo.UnitAreaTreeVo;
import com.yeejoin.equipmanage.mapper.FormInstanceMapper;
import com.yeejoin.equipmanage.remote.RemoteSecurityService;
import com.yeejoin.equipmanage.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.exception.BaseException;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.StringUtil;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.exception.instance.DataNotFound;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author DELL
 */
@Service
public class FormInstanceServiceImpl extends ServiceImpl<FormInstanceMapper, FormInstance> implements IFormInstanceService {

    @Autowired
    private IFormGroupColumnService iFormGroupColumnService;
    @Autowired
    private RemoteSecurityService remoteSecurityService;
    @Autowired
    private IFormGroupService iFormGroupService;
    @Autowired
    private Sequence sequence;
    @Autowired
    private FormInstanceMapper formInstanceMapper;
    @Autowired
    private IEqSourceFileService sourceFileService;
    @Autowired
    IWarehouseStructureService iWarehouseStructureService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ISyncDataService syncDataService;
    @Autowired
    private IAreaService iAreaService;

    @Value("${systemctl.dict.build-type}")
    private String buildType;

    @Value("${systemctl.dict.build-use-type}")
    private String buildUseType;

    @Value("${systemctl.dict.building-structure-type}")
    private String buildingStructureType;

    private final String CODE = "code";

    private final String ORGCODE = "orgCode";

    @Value("${systemctl.sync.switch}")
    private Boolean syncSwitch;

    @Override
    @Transactional(rollbackFor = {BaseException.class, Exception.class})
    public Map<String, Object> createByMap(String groupCode, String companyCode, Map<String, Object> map) {
        //1.查询分组表数据，数据准备用
        Map<String, Object> returnMap = new HashMap<>();
        FormGroup formGroup = iFormGroupService.getByUniqueKey(groupCode);
        //2.查询分组对应的动态表单字段
        List<FormGroupColumn> optionList = iFormGroupColumnService.queryByGroup(groupCode);
        if (CollectionUtils.isEmpty(map) || formGroup == null) {
            return returnMap;
        }
        Long instanceId = sequence.nextId();
        String groupType = formGroup.getGroupType();
        List<FormInstance> entities = new ArrayList<>();
        //3.以数据库现在配置的动态表单字段为准，进行数据插入的准备
        for (FormGroupColumn option : optionList) {
            String stringValue = checkAndFillCode(companyCode, map, groupCode, option);
            FormInstance formInstance = new FormInstance();
            Bean.copyExistPropertis(option, formInstance);
            buildEntry(instanceId, formGroup, entities, option, stringValue, formInstance);
        }
        //4.批量插入
        boolean saveBatch = this.saveBatch(entities);
        if (saveBatch && StringUtils.isNotBlank(groupType) && syncSwitch) {
            //数据同步
            if ("building".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedBuilding(entities);
            } else if ("floor".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedFloor(entities);
            } else if ("room".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedRoom(entities);
            }
        }
        //5.返回值对象(数据暂时未用到)
        returnMap = Bean.listToMap(entities, "fieldName", "fieldValue", FormInstance.class);
        returnMap.put("instanceId", entities.iterator().next().getInstanceId());
        return returnMap;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, BaseException.class})
    public Map<String, Object> updateInstance(Long instanceId, String companyCode, Map<String, Object> map) {
        //1.插入前数据校验
        List<FormInstance> list = this.queryByInstanceId(instanceId);
        if (CollectionUtils.isEmpty(list)) {
            throw new DataNotFound("找不到制定的数据实例");
        }
        String groupCode = list.iterator().next().getGroupCode();
        //2.查询分组表数据，数据准备用
        FormGroup formGroup = iFormGroupService.getByUniqueKey(groupCode);
        // 2.1将list转map,key为字段名（分组下不重复），value值
        Map<Object, FormInstance> instanceMap = Bean.listToMap(list, "fieldName", FormInstance.class);
        //3.以现有字段表数据，为准，进行表字段的更新
        List<FormGroupColumn> optionList = iFormGroupColumnService.queryByGroup(groupCode);
        String groupType = formGroup.getGroupType();
        List<FormInstance> entities = new ArrayList<>();
        for (FormGroupColumn optionModel : optionList) {
            String stringValue = this.checkAndFillCode(companyCode, map, groupCode, optionModel);
            FormInstance instanceModel = instanceMap.get(optionModel.getFieldName());
            if (!ObjectUtils.isEmpty(instanceModel)) {
                instanceModel.setFieldValue(stringValue);
                instanceModel.setCreateDate(new Date());
                entities.add(instanceModel);
            } else {
                FormInstance formInstance = new FormInstance();
                buildEntry(instanceId, formGroup, entities, optionModel, stringValue, formInstance);
            }
        }
        //4.保存
        boolean saveOrUpdateBatch = this.saveOrUpdateBatch(entities);
//        syncDataService.syncCreatedFormInstance(entities);
        if (saveOrUpdateBatch && StringUtils.isNotBlank(groupType) && syncSwitch) {
            //数据同步
            if ("building".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedBuilding(entities);
            } else if ("floor".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedFloor(entities);
            } else if ("room".equalsIgnoreCase(groupType)) {
                syncDataService.syncCreatedRoom(entities);
            }
        }
        //5.返回值对象(数据暂时未用到)
        Map<String, Object> returnMap = Bean.listToMap(list, "fieldName", "fieldValue", FormInstance.class);
        returnMap.put("instanceId", entities.iterator().next().getInstanceId());
        return returnMap;
    }

    private String checkAndFillCode(String companyCode, Map<String, Object> map, String groupCode, FormGroupColumn optionModel) {
        Object value = map.get(optionModel.getFieldName());
        String stringValue = this.fillCode(groupCode, optionModel.getFieldName(), value == null ? null : String.valueOf(value), companyCode);
        // 检验code重复
        if ("code".equals(optionModel.getFieldName())) {
            String instanceId = String.valueOf(map.get("instanceId"));
            int count = this.count(new QueryWrapper<FormInstance>().eq("field_value", stringValue).eq("field_name", "code").ne("instance_id", instanceId == null ? "" : instanceId));
            if (count > 0) {
                if (value == null) {
                    stringValue = checkAndFillCode(companyCode, map, groupCode, optionModel);
                } else {
                    throw new BadRequest("编码重复！");
                }
            }
        }
        if (StringUtils.isEmpty(stringValue) && optionModel.getNotNull()) {
            throw new BadRequest(optionModel.getFieldLabel() + " 不能为空");
        }
        return stringValue;
    }

    private void buildEntry(Long instanceId, FormGroup formGroup, List<FormInstance> entities, FormGroupColumn optionModel, String stringValue, FormInstance formInstance) {
        formInstance.setFieldName(optionModel.getFieldName());
        formInstance.setFieldLabel(optionModel.getFieldLabel());
        formInstance.setDataType(optionModel.getDataType());
        formInstance.setGroupId(optionModel.getGroupId());
        formInstance.setGroupCode(optionModel.getGroupCode());
        formInstance.setQueryStrategy(optionModel.getQueryStrategy());

        formInstance.setFieldValue(stringValue);
        formInstance.setInstanceId(instanceId);
        formInstance.setGroupColumnId(optionModel.getId());
        formInstance.setId(sequence.nextId());
        formInstance.setGroupType(formGroup.getGroupType());
        formInstance.setCreateDate(new Date());
        entities.add(formInstance);
    }

    public List<FormInstance> queryByInstanceId(Long instanceId) {
        QueryWrapper<FormInstance> wrapper = new QueryWrapper<>();
        wrapper.eq("instance_id", instanceId);
        return this.baseMapper.selectList(wrapper);
    }

    @Override
    public Map<String, Object> queryForMap(Long instanceId) {
        Map<String, Object> optionListMap = new HashMap<>();
        List<FormInstance> list = this.queryByInstanceId(instanceId);
        if (!CollectionUtils.isEmpty(list)) {
            List<FormGroupColumn> optionList = iFormGroupColumnService.queryByGroup(list.iterator().next().getGroupCode());
            optionListMap = Bean.listToMap(optionList, "fieldName", "fieldLabel", FormGroupColumn.class);
            Map instanceMap = Bean.listToMap(list, "fieldName", "fieldValue", FormInstance.class);
            for (FormGroupColumn optionModel : optionList) {
                instanceMap.put(optionModel.getFieldName(), this.dataTypeProcess(optionModel.getFieldName(), instanceMap.get(optionModel.getFieldName()), optionModel.getDataType(), instanceMap));
            }
            optionListMap.putAll(instanceMap);
            optionListMap.put("instanceId", instanceId);
            optionListMap.put("createTime", list.iterator().next().getCreateDate());
            optionListMap.put("groupCode", list.iterator().next().getGroupCode());
        }
        return optionListMap;
    }

    @Override
    public List<BuildSearchDTO> getBuildFloorList(BuildSearchDTO dto) {
        return formInstanceMapper.getBuildFloorList(dto);
    }

    @Override
    public List<LinkedHashMap<String, Object>> findByInstanceId(Long instanceId, String fileCategory, Boolean isDetail) {
        List<SourceFile> fileList = sourceFileService.findBySourceId(instanceId);
        LinkedHashMap<String, Object> hashMap = new LinkedHashMap<>();
        if (!fileList.isEmpty()) {
            StringBuffer buffer = new StringBuffer();
            if (StringUtils.isNotEmpty(fileCategory)) {
                List<SourceFile> collect = fileList.stream().filter(item -> fileCategory.equals(item.getFileCategory())).collect(Collectors.toList());
                collect.stream().forEach(item -> buffer.append(item.getFilePath() + ","));
                hashMap.put("key", "建筑照片");
                hashMap.put("value", buffer.toString());
            } else {
                fileList.stream().forEach(item -> buffer.append(item.getFilePath() + ","));
                hashMap.put("key", "建筑照片");
                hashMap.put("value", buffer.toString());
            }
        }
        if (isDetail) {
            List<LinkedHashMap<String, Object>> list = formInstanceMapper.findDetailByInstanceId(instanceId, fileCategory);

            if (!hashMap.isEmpty()) {
                list.add(hashMap);
            }
            return list;
        } else {
            LinkedHashMap<String, Object> map = formInstanceMapper.findByInstanceId(instanceId, fileCategory);
            //建筑类别
            List<DictionarieValueModel> buildTypes = Systemctl.dictionarieClient.dictValues(buildType).getResult();
            //结构类型
            List<DictionarieValueModel> buildStructureType = Systemctl.dictionarieClient.dictValues(buildingStructureType).getResult();
            List<DictionarieValueModel> buildUseTypes = Systemctl.dictionarieClient.dictValues(buildUseType).getResult();

            Map<String, Object> buildTypesMap = buildTypes.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));
            Map<String, Object> buildStructureTypeMap = buildStructureType.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));
            Map<String, Object> buildUseTypeMap = buildUseTypes.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));

            List<LinkedHashMap<String, Object>> list = new ArrayList<>();
            if (map != null && !map.isEmpty()) {
                map.forEach((k, v) -> {
                    LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
                    if (("负责人").equals(k)) {
                        v = remoteSecurityService.getUserById(v.toString()) == null ? v : remoteSecurityService.getUserById(v.toString()).getRealName();
                    }
                    if (("建筑结构").equals(k)) {
                        v = buildTypesMap.get(v);
                    }
                    if (("结构类型").equals(k)) {
                        v = buildStructureTypeMap.get(v);
                    }
                    if (("使用性质").equals(k)) {
                        v = buildUseTypeMap.get(v);
                    }
                    linkedHashMap.put("key", k);
                    linkedHashMap.put("value", v);
                    list.add(linkedHashMap);
                });
                if (!hashMap.isEmpty()) {
                    list.add(hashMap);
                }
            }
            return list;
        }
    }

    @Override
    public Map<String, Object>  getFormInstanceById(Long instanceId) {
        return formInstanceMapper.getFormInstanceById(instanceId);
    }

    @Override
    public Page queryForInstancePage(String groupCode, long current, long size) {
        List<FormGroupColumn> optionList = iFormGroupColumnService.queryByGroup(groupCode);
        Map<String, String[]> parameterMap = request.getParameterMap();
        //说明：parameterMap 为静态map 不可修改，所以需要深拷贝
        Map<String, String[]> localMap = new HashMap<>();
        localMap.putAll(parameterMap);
        localMap.remove("current");
        localMap.remove("size");
        Map<String, String> params = new HashMap<>();
        if (!ValidationUtil.isEmpty(localMap)) {
            for (String key : localMap.keySet()) {
                if (!ValidationUtil.isEmpty(localMap.get(key))) {
                    params.put(key, localMap.get(key)[0]);
                }
            }
        }
        Page page = new Page();
        page.setCurrent(current);
        page.setSize(size);
        Map<String, Object> fieldNames = Bean.listToMap(optionList, "fieldName", "queryStrategy", FormGroupColumn.class);
        Page<Map<String, Object>> resultList = this.getBaseMapper().queryInstancePage(page, groupCode, fieldNames, params);
        if (!ValidationUtil.isEmpty(resultList)) {
            for (FormGroupColumn optionModel : optionList) {
                for (Map<String, Object> instanceMap : resultList.getRecords()) {
                    instanceMap.put(optionModel.getFieldName(), this.dataTypeProcess(optionModel.getFieldName(), instanceMap.get(optionModel.getFieldName()), optionModel.getDataType(), instanceMap));
                }
            }
        }
        return resultList;
    }

    @Override
    public List<Map<String, Object>> queryForMapList(String groupCode, Map<String, String> params) {
        List<Map<String, Object>> returnList = new ArrayList<>();
        List<FormGroupColumn> optionList = iFormGroupColumnService.queryByGroup(groupCode);
        Map<String, Object> fieldNames = Bean.listToMap(optionList, "fieldName", "queryStrategy", FormGroupColumn.class);
        returnList = this.baseMapper.queryForMapList(groupCode, fieldNames, params);
        for (FormGroupColumn optionModel : optionList) {
            for (Map<String, Object> instanceMap : returnList) {
                instanceMap.put(optionModel.getFieldName(), this.dataTypeProcess(optionModel.getFieldName(), instanceMap.get(optionModel.getFieldName()), optionModel.getDataType(), instanceMap));
            }
        }
        return returnList;
    }

    @Override
    public Boolean deleteInstanceById(Long instanceId) {
        //1.校验 TODO,带完善
        //2.删除
        QueryWrapper<FormInstance> fqw = new QueryWrapper<>();
        fqw.eq("field_name", "parentId");
        fqw.eq("field_value", instanceId);
        List<FormInstance> formInstances = this.baseMapper.selectList(fqw);
        if (formInstances != null && formInstances.size() > 0) {
            throw new BadRequest("该建筑下存在子建筑，请先清空子建筑后再进行删除！");
        }
        formInstanceMapper.deleteStuById(instanceId);
        return this.baseMapper.delete(new QueryWrapper<FormInstance>().lambda().eq(FormInstance::getInstanceId, instanceId)) > 0;
    }

    private Object dataTypeProcess(String fieldName, Object value, String dataType, Map instanceMap) {
        Object retValue = value;
        if (!ValidationUtil.isEmpty(value)) {
            GroupColumnDataType optionDataType = GroupColumnDataType.valueOf(dataType);
            switch (optionDataType) {
                case InstanceId:
                    List<Long> instanceIds = StringUtil.String2LongList(String.valueOf(value));
                    List<Map<String, Object>> mapList = new ArrayList<>();
                    instanceIds.forEach((id) -> mapList.add(queryForMap(id)));
                    retValue = mapList;
                    break;
                case Enum:
                    Map<String, Map<String, Object>> map = iFormGroupColumnService.processEnumData(fieldName, String.valueOf(value));
                    instanceMap.putAll(map);
                    break;
                default:
                    break;
            }
        }
        return retValue;
    }

    @Override
    public List<Map<String, Object>> getSpecialChildrenList(String parentId) {
        return this.baseMapper.querySpecialChildrenList(parentId);
    }

    private String fillCode(String groupCode, String fieldName, String value, String companyCode) {
        if (CODE.equals(fieldName) && StringUtils.isEmpty(value)) {
            return RandomUtil.buildNo(GroupCodeEnum.getInstance(groupCode).getSequenceType(), companyCode);
        } else if (ORGCODE.equals(fieldName) && StringUtils.isEmpty(value)) {
            return companyCode;
        }
        return value == null ? "" : value;
    }

    /**
     * @param dto 查询参数
     * @Description 分页查询
     * @Return List<Map < String, Object>>
     * @Date 2020/12/19 11:47
     */
    @Override
    public Page queryPage(Page page, BuildSearchDTO dto) {
        String ids[] = dto.getInstanceId().split(",");
        if (ids.length > 0) {
            dto.setInstanceIds(Stream.of(ids).collect(Collectors.toList())
                    .stream()
                    .map(x -> Long.valueOf(x)).collect(Collectors.toList()));
        }
        return baseMapper.queryPage(page, dto);
    }

    @Override
    public List<Map<String, Object>> queryPage(BuildSearchDTO dto) {
        String ids[] = dto.getInstanceId().split(",");
        if (ids.length > 0) {
            dto.setInstanceIds(Stream.of(ids).collect(Collectors.toList())
                    .stream()
                    .map(x -> Long.valueOf(x)).collect(Collectors.toList()));
        }
        return baseMapper.queryPage(dto);
    }

    @Override
    public Page roomPage(Page page, BuildSearchDTO dto) {
        String ids[] = dto.getInstanceId().split(",");
        if (ids.length > 0 && !ids[0].equals("")) {
            dto.setInstanceIds(Stream.of(ids).collect(Collectors.toList())
                    .stream()
                    .map(x -> Long.valueOf(x)).collect(Collectors.toList()));
            return baseMapper.roomPage(page, dto);
        }
        return new Page();
    }

    @Override
    public Page floorPage(Page page, BuildSearchDTO dto) {
        String ids[] = dto.getInstanceId().split(",");
        if (ids.length > 0) {
            dto.setInstanceIds(Stream.of(ids).collect(Collectors.toList())
                    .stream()
                    .map(x -> Long.valueOf(x)).collect(Collectors.toList()));
        }
        return baseMapper.roomPage(page, dto);
    }

    /**
     * @param dto 查询参数
     * @Description 查询列表
     * @Return List<Map < String, Object>>
     * @Date 2020/12/19 11:47
     */
    @Override
    public List<Map<String, Object>> roomPage(BuildSearchDTO dto) {
        return baseMapper.roomPage(dto);
    }

    /**
     * @param instanceId
     * @Description 根据parentId查询其下资源（楼层、房间）
     * @Return List<Map < String, Object>>
     * @Date 2020/12/19 15:06
     */
    @Override
    public List<Map<String, Object>> queryFloorRoom(List<Long> instanceId) {
        return baseMapper.queryFloorRoom(instanceId);
    }

    @Override
    public List<Map<String, Object>> getBuildVideoListCount(List<String> bizOrgCodeList) {
        return formInstanceMapper.getBuildVideoListCount(bizOrgCodeList);
    }

    @Override
    public List<Map<String, Object>> getColaBuildVideoListCount(BuildingVideoListVO dto) {
        return formInstanceMapper.getColaBuildVideoListCount(dto);
    }

    @Override
    public void unbindRegionRelation(Long instanceId) {
        this.baseMapper.clearRegionBind(instanceId);
    }

    @Override
    public List<UnitAreaTreeVo> getValueByColumn(Long instanceId, String bizOrgcode) {
        List<UnitAreaTreeVo> listTree = new ArrayList<>();
        LambdaQueryWrapper<FormInstance> queryWrapper = new LambdaQueryWrapper<>();
        if (instanceId != 0L) {
            queryWrapper.eq(FormInstance::getInstanceId, instanceId);
        }
        queryWrapper.eq(FormInstance::getFieldName, "belongAreaId");
        FormInstance formInstance = formInstanceMapper.selectOne(queryWrapper);
        if (formInstance != null && formInstance.getFieldValue() != null && !"".equals(formInstance.getFieldValue())) {
            long fieldValue = Long.parseLong(formInstance.getFieldValue());
            listTree = iAreaService.getAreaTreeVoById(fieldValue, bizOrgcode);
        }

        return listTree;
    }

    @Override
    public List<Map<String, Long>> getBuildVideoCount() {
        return formInstanceMapper.getBuildVideoCount();
    }
}
