package com.yeejoin.amos.boot.module.common.biz.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.ObjectUtils;
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.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.common.api.dto.AttachmentDto;
import com.yeejoin.amos.boot.module.common.api.dto.KeySiteDateDto;
import com.yeejoin.amos.boot.module.common.api.dto.KeySiteDto;
import com.yeejoin.amos.boot.module.common.api.dto.KeySiteExcleDto;
import com.yeejoin.amos.boot.module.common.api.dto.OrgMenuDto;
import com.yeejoin.amos.boot.module.common.api.entity.KeySite;
import com.yeejoin.amos.boot.module.common.api.entity.OrgUsr;
import com.yeejoin.amos.boot.module.common.api.entity.SourceFile;
import com.yeejoin.amos.boot.module.common.api.enums.OrgPersonEnum;
import com.yeejoin.amos.boot.module.common.api.feign.EquipFeignClient;
import com.yeejoin.amos.boot.module.common.api.mapper.KeySiteMapper;
import com.yeejoin.amos.boot.module.common.api.mapper.OrgUsrMapper;
import com.yeejoin.amos.boot.module.common.api.service.IKeySiteService;
import com.yeejoin.amos.boot.module.common.api.service.IOrgUsrService;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;

/**
 * 重点部位服务实现类
 *
 * @author system_generator
 * @date 2021-07-26
 */
@Service
public class KeySiteServiceImpl extends BaseService<KeySiteDto, KeySite, KeySiteMapper> implements IKeySiteService {

	@Autowired
	KeySiteMapper keySiteMapper;

	@Autowired
	SourceFileServiceImpl sourceFileService;

	@Autowired
	OrgUsrMapper orgUsrMapper;

	@Autowired
	IOrgUsrService iOrgUsrService;

	@Autowired
	EquipFeignClient equipFeignClient;

	@Autowired
	private SnowflakeIdUtil sequence;

	@Value("${auth-key-key-site:key_site_info}")
	private String authKey;

	@Autowired
	private RedisUtils redisUtils;

	/**
	 * 分页查询
	 */
	public IPage<KeySiteDto> getPageList(Page<KeySiteDto> page, String name, Long buildingId, String fireEnduranceRate,
			String useNature, String fireFacilitiesInfo, String bizOrgCode) {
		List<Long> ids = null;
		if (buildingId != null&& buildingId!=-1 && buildingId.intValue() != 0) {
			ids = getNodeAllnodeIds(buildingId);
		}
		return keySiteMapper.getPageList(page, name, ids, fireEnduranceRate, useNature, fireFacilitiesInfo, bizOrgCode);
	}

	@Override
	public List<Object> getBuildTree() {
		ResponseModel<Object> response = equipFeignClient.getBuildingTree();
		if (200 == response.getStatus() && ObjectUtils.isNotEmpty(response.getResult())) {
			return JSONArray.parseArray(JSON.toJSONString(response.getResult()));
		}
		return null;
	}

	/**
	 * 列表查询 示例
	 */
	@Override
	public List<KeySiteDto> queryForKeySiteList(String name, Long buildingId, String fireEnduranceRate,
			String useNature, String fireFacilitiesInfo, String bizOrgCode) {
		return keySiteMapper.getKeySiteList(name, buildingId, fireEnduranceRate, useNature, fireFacilitiesInfo,
				bizOrgCode);
	}

	@Override
	public List<KeySiteExcleDto> exportToExcel(String name, Long buildingId, String fireEnduranceRate, String useNature,
			String fireFacilitiesInfo, String bizOrgCode) {
		// 导出模板增加权限
		ReginParams reginParams = JSONObject.parseObject(redisUtils
				.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(),
				ReginParams.class);
		// 权限处理

		String bizOrgCodeNew = reginParams.getPersonIdentity().getBizOrgCode();

		List<KeySiteDto> list = this.queryForKeySiteList(name, buildingId, fireEnduranceRate, useNature,
				fireFacilitiesInfo, bizOrgCodeNew);
		List<KeySiteExcleDto> excleList = new ArrayList<>();
		list.forEach(i -> {
			KeySiteExcleDto keySiteExcleDto = new KeySiteExcleDto();
			Bean.copyExistPropertis(i, keySiteExcleDto);
			if (i.getFirePreventionFlag()) {
				keySiteExcleDto.setFirePreventionFlagName("有");
			} else {
				keySiteExcleDto.setFirePreventionFlagName("无");
			}
			keySiteExcleDto.setUseNature(i.getUseNatureName());
			keySiteExcleDto.setBelongName(i.getBelongName());
			keySiteExcleDto.setFireEnduranceRate(i.getFireEnduranceRateName());
			excleList.add(keySiteExcleDto);
		});
		return excleList;
	}

	@Override
	public boolean deleteById(List<Long> sequenceNbrList) {
		if (ObjectUtils.isEmpty(sequenceNbrList)) {
			return false;
		}
		try {
			sequenceNbrList.stream().forEach(i -> {
				KeySite keySite = keySiteMapper.selectById(i);
				if (keySite != null) {
					keySite.setIsDelete(true);
					keySiteMapper.updateById(keySite);
				}
			});
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public KeySiteDto save(KeySiteDto model) {
		long sequenceId = sequence.nextId();
		KeySite keySite = new KeySite();
		Bean.copyExistPropertis(model, keySite);
		keySite.setSequenceNbr(sequenceId);
		model.setSequenceNbr(sequenceId);
		this.save(keySite);
		saveAttachments(model);
		// TODO Auto-generated method stub
		return model;
	}

	public void saveAttachments(KeySiteDto keySiteDto) {
		if (!ValidationUtil.isEmpty(keySiteDto.getAttachments())) {
			List<SourceFile> sourceFiles = Lists.newArrayList();
			Map<String, List<AttachmentDto>> attachmentMap = keySiteDto.getAttachments();
			attachmentMap.entrySet().forEach(entry -> {
				List<AttachmentDto> atts = entry.getValue();
				sourceFiles.addAll(attachment2SourceFile(entry.getKey(), atts));
			});
			sourceFileService.saveSourceFile(keySiteDto.getSequenceNbr(), sourceFiles);
		}
	}

	private List<SourceFile> attachment2SourceFile(String type, List<AttachmentDto> attachmentDtoList) {
		List<SourceFile> sourceFiles = Lists.newArrayList();
		if (!ValidationUtil.isEmpty(attachmentDtoList)) {
			attachmentDtoList.forEach(a -> {
				SourceFile s = new SourceFile();
				s.setFilePath(a.getUrl());
				s.setFileName(a.getName());
				s.setFileCategory(type);
				sourceFiles.add(s);
			});
		}
		return sourceFiles;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean update(KeySiteDto keySite, AgencyUserModel userInfo) {
		KeySite entity = new KeySite();
		Bean.copyExistPropertis(keySite, entity);
		entity.setIsDelete(false);
		entity.setRecDate(new Date());
		entity.setRecUserId(userInfo.getUserId());
		entity.setRecUserName(userInfo.getRealName());
		List<String> ids = new ArrayList<String>();
		ids.add(entity.getBuildingId().toString());
		Map<String, String> map3 = getNodeAllParentIds(ids);
		entity.setParentBuildingId(map3.get(entity.getBuildingId().toString()));
		int num = keySiteMapper.updateById(entity);
		Map<String, List<AttachmentDto>> map = keySite.getAttachments();
		if (ObjectUtils.isNotEmpty(map)) {
			this.saveAttachments(keySite);
		}
		if (num > 0) {
			return true;
		}
		return false;
	}

	@Override
	public List<OrgMenuDto> getOrgUserTree(ReginParams reginParams) {
		List<OrgUsr> comDeptList = iOrgUsrService.getListByBizOrgTypeCode(
				OrgPersonEnum.公司.getKey() + "," + OrgPersonEnum.部门.getKey(),
				reginParams.getPersonIdentity().getBizOrgCode());
		List<KeySite> keySiteList = this.list(new LambdaQueryWrapper<KeySite>().eq(BaseEntity::getIsDelete, false));
		comDeptList = comDeptList.stream().map(c -> c.setTotal(keySiteList.stream()
				.filter(k -> StringUtils.isNotBlank(k.getBizOrgCode()) && k.getBizOrgCode().contains(c.getBizOrgCode()))
				.count())).collect(Collectors.toList());
		List<OrgMenuDto> menuList = comDeptList.stream().map(o -> {
			/*
			 * OrgMenuDto menu = new OrgMenuDto(o.getSequenceNbr(), o.getBizOrgName() + " ("
			 * + o.getTotal() + ")", ObjectUtils.isEmpty(o.getParentId()) ? 0L :
			 * Long.valueOf(o.getParentId()), o.getBizOrgType(), false, o.getBizOrgCode());
			 */
			OrgMenuDto menu = new OrgMenuDto(o.getSequenceNbr(), o.getBizOrgName(),
					ObjectUtils.isEmpty(o.getParentId()) ? 0L : Long.valueOf(o.getParentId()), o.getBizOrgType(), false,
					o.getBizOrgCode());
			return menu;
		}).collect(Collectors.toList());
		return buildTreeParallel(menuList);
	}

	public static List<OrgMenuDto> buildTreeParallel(List<OrgMenuDto> menuList) {

		List<OrgMenuDto> result = new ArrayList<>();
		Map<Long, OrgMenuDto> map = new HashMap<>(menuList.size());
		menuList.forEach(e -> map.put(e.getKey(), e));
		Set<? extends Map.Entry<Long, ? extends OrgMenuDto>> entries = map.entrySet();
		entries.stream().forEach(entry -> {
			OrgMenuDto value = entry.getValue();
			if (value != null) {
				OrgMenuDto treeDto = map.get(value.getParentId());
				if (treeDto != null) {
					List<OrgMenuDto> children = treeDto.getChildren();
					if (children == null) {
						children = new ArrayList<>();
						treeDto.setChildren(children);
					}
					children.add(value);
				} else {
					result.add(value);
				}
			}
		});
		return result;
	}

	@Override
	public KeySiteDto getSequenceNbr(Long sequenceNbr) {
		return keySiteMapper.getSequenceNbr(sequenceNbr);
	}

	@Override
	public boolean saveExcel(List<KeySiteExcleDto> excelDtoList) {
		Map<String, String> maps = getAllBuildingIdForParentBuilingIds(excelDtoList);
		List<KeySite> excelList = new ArrayList<KeySite>();

		Map<String, Object> param = new HashMap<>();
		param.put("bizOrgCode", null);
		param.put("type", null);

		List<OrgUsr> comDeptList = orgUsrMapper.companyTreeByUserAndType(param);
		Map<Long, OrgUsr> comDeptMap = comDeptList.stream()
				.collect(Collectors.toMap(BaseEntity::getSequenceNbr, Function.identity()));
		for (KeySiteExcleDto keySiteExcleDto : excelDtoList) {
			KeySite keySiteDto = new KeySite();
			Bean.copyExistPropertis(keySiteExcleDto, keySiteDto);
			keySiteDto.setIsDelete(false);
			if (StringUtils.isNotBlank(keySiteExcleDto.getBelongName())
					&& keySiteExcleDto.getBelongName().contains("@")) {
				keySiteDto.setBelongId(Long.parseLong(keySiteExcleDto.getBelongName().split("@")[1]));
				keySiteDto
						.setBizOrgCode(comDeptMap.getOrDefault(keySiteDto.getBelongId(), new OrgUsr()).getBizOrgCode());
				keySiteDto
						.setBizOrgName(comDeptMap.getOrDefault(keySiteDto.getBelongId(), new OrgUsr()).getBizOrgName());
			}
			if (StringUtils.isNotBlank(keySiteExcleDto.getBuildingName())
					&& keySiteExcleDto.getBuildingName().contains("@")) {
				String[] fireEnduranceRateArray = keySiteExcleDto.getBuildingName().split("@");
				keySiteDto.setBuildingId(Long.parseLong(fireEnduranceRateArray[1]));
				keySiteDto.setBuildingName(fireEnduranceRateArray[0]);
				if (maps.containsKey(fireEnduranceRateArray[1])) {
					keySiteDto.setParentBuildingId(maps.get(fireEnduranceRateArray[1]));
				}

			}
			if (StringUtils.isNotBlank(keySiteExcleDto.getFireEnduranceRate())
					&& keySiteExcleDto.getFireEnduranceRate().contains("@")) {
				String[] fireEnduranceRateArray = keySiteExcleDto.getFireEnduranceRate().split("@");
				if (fireEnduranceRateArray.length > 1) {
					keySiteDto.setFireEnduranceRate(fireEnduranceRateArray[1]);
				}
				keySiteDto.setFireEnduranceRateName(fireEnduranceRateArray[0]);
			}
			if (StringUtils.isNotBlank(keySiteExcleDto.getUseNature())
					&& keySiteExcleDto.getUseNature().contains("@")) {
				String[] useNatureArray = keySiteExcleDto.getUseNature().split("@");
				if (useNatureArray.length > 1) {
					keySiteDto.setUseNature(useNatureArray[1]);
				}
				keySiteDto.setUseNatureName(useNatureArray[0]);
			}
			if ("有".equals(keySiteExcleDto.getFirePreventionFlagName())) {
				keySiteDto.setFirePreventionFlag(true);
			} else {
				keySiteDto.setFirePreventionFlag(false);
			}
			keySiteDto = Bean.toPo(getCurrentInfo(), keySiteDto);
			excelList.add(keySiteDto);
		}
		return this.saveBatch(excelList);
	}

	public Map<String, String> getAllBuildingIdForParentBuilingIds(List<KeySiteExcleDto> excelDtoList) {
		List<String> list = new ArrayList<String>();
		for (KeySiteExcleDto keySiteExcleDto : excelDtoList) {
			if (StringUtils.isNotBlank(keySiteExcleDto.getBuildingName())
					&& keySiteExcleDto.getBuildingName().contains("@")) {
				String[] fireEnduranceRateArray = keySiteExcleDto.getBuildingName().split("@");
				list.add(fireEnduranceRateArray[1]);
			}
		}
		return getNodeAllParentIds(list);
	}

	public BaseEntity getCurrentInfo() {
		BaseEntity userModel = new BaseEntity();
		/*
		 * String keyString= RequestContext.getExeUserId(); String
		 * token=RequestContext.getToken(); ReginParams params =
		 * JSONObject.parseObject(redisUtils .get(RedisKey.buildReginKey(keyString,
		 * token)).toString(), ReginParams.class);
		 */
		userModel.setRecUserId("3141675");
		userModel.setRecUserName("admin_jcs");
		userModel.setRecDate(new Date());
		return userModel;
	}

	@Override
	public List<OrgMenuDto> getBuildAndKeyTree(Long sequenceNbr) {
		LambdaQueryWrapper<KeySite> mapper = new LambdaQueryWrapper<KeySite>();
		mapper.eq(KeySite::getBuildingId, sequenceNbr);
		mapper.eq(KeySite::getIsDelete, false);
		List<KeySite> list = this.baseMapper.selectList(mapper);
		if (list == null || list.size() == 0) {
			return null;
		}
		String buildNameString = list.get(0).getBuildingName();
		List<OrgMenuDto> menuList = list.stream().map(o -> {
			OrgMenuDto menu = new OrgMenuDto(o.getSequenceNbr(), o.getName(),
					ObjectUtils.isEmpty(o.getBelongId()) ? 0L : Long.valueOf(o.getBelongId()), null, false, null);
			return menu;
		}).collect(Collectors.toList());
		List<OrgMenuDto> list1 = new ArrayList<OrgMenuDto>();
		OrgMenuDto orgMenuDto = new OrgMenuDto();
		orgMenuDto.setKey(sequenceNbr);
		orgMenuDto.setValue(sequenceNbr);
		orgMenuDto.setChildren(buildTreeParallel(menuList));
		orgMenuDto.setName(buildNameString);
		orgMenuDto.setTitle(buildNameString);
		list1.add(orgMenuDto);
		return list1;
	}

	@Override
	public List<KeySiteDateDto> getKeySiteDate(Long id) {
		return keySiteMapper.getKeySiteDate(id);
	}

	public List<String> getAddress() {
		return keySiteMapper.getAddress();
	}

	@Override
	public List<KeySite> getKeySiteDateByNameLike(Long companyId) {
		LambdaQueryWrapper<KeySite> mapper = new LambdaQueryWrapper<KeySite>();
		mapper.eq(KeySite::getIsDelete, false);
		if (companyId != null && companyId.longValue() != 0) {
			mapper.eq(KeySite::getBelongId, companyId);
		}
		return this.baseMapper.selectList(mapper);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Map<String, Object>> keySiteCountAndBuildingTree(String bizOrgCode) {
		int allCount = 0;
		Map<String, Integer> keySiteCountMap = parseKeySiteCount(bizOrgCode);
		ResponseModel<Object> response = equipFeignClient.getBuildingTree();
		List<Map<String, Object>> buildingMapList = (List<Map<String, Object>>) response.getResult();
		if (buildingMapList == null || buildingMapList.size() < 1) {
			return null;
		}
		List<Map<String, Object>> childrens  = ((List<Map<String, Object>>) buildingMapList.get(0).get("children")).stream().filter(i->i.containsKey("bizOrgCode") && i.get("bizOrgCode").toString().contains(bizOrgCode)).collect(Collectors.toList());
		Map<String, Object> reMap = parseTree(childrens,
				keySiteCountMap, allCount);
		Map<String, Object> fristMap = buildingMapList.get(0);
		fristMap.put("id", 0);
		fristMap.put("name", fristMap.get("instanceName") + "(" + reMap.get("allCount") + ")");
		fristMap.put("children", reMap.get("children"));
		buildingMapList.clear();
		buildingMapList.add(fristMap);
		return buildingMapList;
	}

	@SuppressWarnings("unchecked")
	private Map<String, Object> parseTree(List<Map<String, Object>> children, Map<String, Integer> keySiteCountMap,
			int allCount) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		if (!ValidationUtil.isEmpty(children)) {
			for (Map<String, Object> child : children) {
				if (child.get("id") != null) {
					if (keySiteCountMap.containsKey(child.get("id").toString())) {
						allCount = allCount + keySiteCountMap.get(child.get("id").toString()).intValue();
						child.put("name",
								child.get("name") + "(" + keySiteCountMap.get(child.get("id").toString()) + ")");
					} else {
						child.put("name", child.get("name") + "(" + 0 + ")");
					}
				} else {
					child.put("name", child.get("name") + "(" + 0 + ")");
				}
				if (!ValidationUtil.isEmpty(child.get("children"))) {
					parseTree((List<Map<String, Object>>) child.get("children"), keySiteCountMap, allCount);
				}
			}
		}
		resultMap.put("children", children);
		resultMap.put("allCount", allCount);
		return resultMap;
	}

	private Map<String, Integer> parseKeySiteCount(String bizOrgCode) {
		Map<String, Integer> map = new HashMap<String, Integer>();

		List<Map<String, Object>> list = keySiteMapper.getKeySiteCount(bizOrgCode);
		for (Map<String, Object> map2 : list) {
			Object parentBuilingIdString = map2.get("parent_building_id");
			if (ObjectUtils.isEmpty(parentBuilingIdString)) {
				continue;
			}
			String[] parentBuilingIdArray = parentBuilingIdString.toString().split(",");
			for (int i = 0; i < parentBuilingIdArray.length; i++) {
				if (map.containsKey(parentBuilingIdArray[i])) {
					int num = map.get(parentBuilingIdArray[i]).intValue();
					num = num + Integer.parseInt(map2.get("count").toString());
					map.put(parentBuilingIdArray[i], num);
				} else {
					map.put(parentBuilingIdArray[i], Integer.parseInt(map2.get("count").toString()));
				}
			}
		}
		return map;

	}

	public Map<String, String> getNodeAllParentIds(List<String> ids) {
		Map<String, String> map = new HashMap<String, String>();
		ResponseModel<List<Map<String, Object>>> response = equipFeignClient.getBuildingTreeList();
		List<Map<String, Object>> responseList = response.getResult();
		if (response.getResult() == null && response.getResult().size() < 1) {
			return null;
		}
		ids.stream().forEach(i -> {

			String tegartString = getNodeAllParentIds(responseList, i, i);
			map.put(i, tegartString);
		});
		return map;
	}

	private String getNodeAllParentIds(List<Map<String, Object>> list, String id, String tegartString) {
		for (Map<String, Object> map : list) {
			if (map.get("id").toString().equals(id) && map.get("parentId") != null) {
				tegartString = tegartString + "," + map.get("parentId").toString();
				 getNodeAllParentIds(list, map.get("parentId").toString(), tegartString);
			}
		}
		return tegartString;
	}

	public List<Long> getNodeAllnodeIds(Long id) {
		List<Long> resultList = new ArrayList<Long>();
		resultList.add(id);
		ResponseModel<List<Map<String, Object>>> response = equipFeignClient.getBuildingTreeList();
		List<Map<String, Object>> responseList = response.getResult();
		if (response.getResult() == null && response.getResult().size() < 1) {
			return null;
		}
		return getNodeAllnodeIds(resultList, responseList, id.toString());
	}

	private List<Long> getNodeAllnodeIds(List<Long> resultList, List<Map<String, Object>> list, String id) {
		for (Map<String, Object> map : list) {
			if (map.get("parentId").toString().equals(id) && map.get("parentId") != null) {
				resultList.add(Long.parseLong(map.get("id").toString()));
				getNodeAllnodeIds(resultList, list, map.get("id").toString());
			}
		}
		return resultList;
	}
}
