package com.yeejoin.equipmanage.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import com.yeejoin.equipmanage.common.enums.SourceTypeEnum;
import com.yeejoin.equipmanage.common.utils.SpringUtils;
import com.yeejoin.equipmanage.service.ISourceStatistics;
import com.yeejoin.equipmanage.service.impl.SourcesStatisticsImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.typroject.tyboot.core.foundation.enumeration.UserType;
import org.typroject.tyboot.core.restful.doc.TycloudOperation;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.equipmanage.common.entity.DynamicFormGroup;
import com.yeejoin.equipmanage.common.entity.EquipmentCategory;
import com.yeejoin.equipmanage.common.entity.dto.EquipTypeAmountDTO;
import com.yeejoin.equipmanage.common.entity.vo.EquipTypeAmountVO;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentCategoryCountVO;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentCategoryTypeTreeVO;
import com.yeejoin.equipmanage.common.utils.CommonResponseUtil;
import com.yeejoin.equipmanage.common.utils.NameUtils;
import com.yeejoin.equipmanage.common.vo.IndustryVo;
import com.yeejoin.equipmanage.context.SpringContextHolder;
import com.yeejoin.equipmanage.event.EquipmentTreeListEvent;
import com.yeejoin.equipmanage.service.IEqDynamicFormGroupService;
import com.yeejoin.equipmanage.service.IEquipmentCategoryService;
import com.yeejoin.equipmanage.service.IIndustryService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/**
 * 装备分类
 *
 * @author wujiang
 * @date 2020-07-07
 */
@RestController
@Api(tags = "装备分类Api")
@RequestMapping(value = "/equipment-category", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class EquipmentCategoryController extends AbstractBaseController {

	@Autowired
	IEquipmentCategoryService iEquipmentCategoryService;
	@Value("${equipment.type}")
	String equipmentCategoryLeftTypeCode;
	@Autowired
	IIndustryService iIndustryService;
	@Autowired
    IEqDynamicFormGroupService iEqDynamicFormGroupService;

	@Autowired
	private RedisUtils redisUtils;

	@Autowired
	ISourceStatistics iSourceStatistics;

	@Value("${redis_car_type_count}")
	private String carTypeAndCount;

	@Value("${redis_equip_type_count}")
	private String equipTypeAndCount;

	private static final String equipmentTreeListAll = "equipmentTreeListAll";
	private static final String equipmentTreeListIndustry = "equipmentTreeListIndustry";
	// 装备redis缓存key前缀
	private static final String prefix = "equipmentTreeList";

	/**
	 * 新增装备分类
	 * 
	 * @return
	 */
	@RequestMapping(value = "/save", method = RequestMethod.POST)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "POST", value = "新增装备分类", notes = "新增装备分类")
	public EquipmentCategory saveEquipmentCategory(HttpServletRequest request,
			@RequestBody EquipmentCategory equipmentCategory) {
		EquipmentCategory equipmentCategoryInstance = iEquipmentCategoryService
				.saveEquipmentCategory(equipmentCategory);
		EquipmentCategoryController controllerProxy = SpringUtils.getBean(EquipmentCategoryController.class);
		controllerProxy.refreshAllCount();
		return equipmentCategoryInstance;
	}

	@Async
	public void refreshAllCount() {
		// 清空单位装备分类树缓存
		redisUtils.getAndDeletePatternKeys(carTypeAndCount + "*");
		// 清空车辆分类树缓存
		redisUtils.getAndDeletePatternKeys(equipTypeAndCount + "*");
		redisUtils.getAndDeletePatternKeys("iotTypeAndCount" + "*");
		// 清空单位分类数量统计缓存
		redisUtils.getAndDeletePatternKeys(SourcesStatisticsImpl.PREFIX_CATEGORY_COUNT + "*");
		// 刷新装备单位分类数量缓存
		iSourceStatistics.initAllCategoryStatisticsData(SourceTypeEnum.EQUIPMENT);
		// 刷新车辆单位分类数量缓存
		iSourceStatistics.initAllCategoryStatisticsData(SourceTypeEnum.CAR);

		iSourceStatistics.initAllCategoryStatisticsData(SourceTypeEnum.IOT);
	}

	/**
	 * 根据id删除
	 * 
	 * @param ids
	 * @return
	 */
	@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "DELETE", value = "根据id删除", notes = "根据id删除")
	public ResponseModel deleteById(@ApiParam(value = "装备分类id数组", required = true) @RequestParam("ids") String... ids) {
		List<String> idList = new ArrayList<String>(Arrays.asList(ids));
		QueryWrapper<EquipmentCategory> queryWrapper = new QueryWrapper<EquipmentCategory>();
		queryWrapper.lambda().in(EquipmentCategory::getParentId, idList);
		int count = this.iEquipmentCategoryService.count(queryWrapper);
		if (count > 0) {
			return CommonResponseUtil.failure("此装备分类下存在子分类信息，请先删除子节点！");
		}
		int num = iEquipmentCategoryService.checkUsed(idList);
		if (num > 0) {
			return CommonResponseUtil.failure("此装备类别或子类别已被引用，不能删除！");
		}
		// 记录删除数据的code和消防设备的类型
		Set<String> idSet = new HashSet<>();
		Set<String> typeSet = new HashSet<>();
		if (idList.size() > 0) {
			for (String id : idList) {
				EquipmentCategory equipmentCategory = iEquipmentCategoryService.getById(id);
				if (equipmentCategory != null) {
					String industrycode = equipmentCategory.getIndustryCode();
					if ("2".equals(industrycode)) {
						String code = equipmentCategory.getCode();
						if (code != null && !"".equals(code)) {
							String codeFirst = code.substring(0, 1);
							typeSet.add(codeFirst);
						}

					}
					idSet.add(industrycode);
				}
			}
		}
		boolean removeFlag = iEquipmentCategoryService.removeByIds(idList);
		if (removeFlag) {
			// 更新缓存
			SpringContextHolder.publishEvent(new EquipmentTreeListEvent(this, idSet, typeSet));
			EquipmentCategoryController controllerProxy = SpringUtils.getBean(EquipmentCategoryController.class);
			controllerProxy.refreshAllCount();
		}
		return CommonResponseUtil.success(removeFlag);
	}

	/**
	 * 修改装备分类
	 * 
	 * @return
	 */
	@RequestMapping(value = "/updateById", method = RequestMethod.PUT)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "PUT", value = "修改装备分类", notes = "修改装备分类")
	public boolean updateByIdEquipmentCategory(HttpServletRequest request,
			@RequestBody EquipmentCategory equipmentCategory) {
		boolean updateFlag = iEquipmentCategoryService.updateById(equipmentCategory);
		iEqDynamicFormGroupService.update(new UpdateWrapper<DynamicFormGroup>()
				.eq("group_code", equipmentCategory.getCode()).set("group_name", equipmentCategory.getName()));
		if (updateFlag) {
			// 更新缓存
			EquipmentCategoryController controllerProxy = SpringUtils.getBean(EquipmentCategoryController.class);
			controllerProxy.refreshAllCount();
			SpringContextHolder.publishEvent(new EquipmentTreeListEvent(this, equipmentCategory));
		}
		return updateFlag;
	}

	/**
	 * 根据id查询
	 * 
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "根据id查询", notes = "根据id查询")
	public EquipmentCategory selectById(HttpServletRequest request, @PathVariable Long id) {
		return iEquipmentCategoryService.getById(id);
	}

	/**
	 * 列表分页查询
	 * 
	 * @return
	 */
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "列表分页查询", notes = "列表分页查询")
	public IPage<EquipmentCategory> listPage(String pageNum, String pageSize, EquipmentCategory equipmentCategory) {

		Page<EquipmentCategory> pageBean;
		QueryWrapper<EquipmentCategory> equipmentCategoryQueryWrapper = new QueryWrapper<>();
		Class<? extends EquipmentCategory> aClass = equipmentCategory.getClass();
		Arrays.stream(aClass.getDeclaredFields()).forEach(field -> {
			try {
				field.setAccessible(true);
				Object o = field.get(equipmentCategory);
				if (o != null) {
					Class<?> type = field.getType();
					String name = NameUtils.camel2Underline(field.getName());
					if (type.equals(Integer.class)) {
						Integer fileValue = (Integer) field.get(equipmentCategory);
						equipmentCategoryQueryWrapper.eq(name, fileValue);
					} else if (type.equals(Long.class)) {
						Long fileValue = (Long) field.get(equipmentCategory);
						equipmentCategoryQueryWrapper.eq(name, fileValue);
					} else if (type.equals(String.class)) {
						String fileValue = (String) field.get(equipmentCategory);
						equipmentCategoryQueryWrapper.eq(name, fileValue);
					} else {
						String fileValue = (String) field.get(equipmentCategory);
						equipmentCategoryQueryWrapper.eq(name, fileValue);
					}
				}
			} catch (Exception e) {
			}
		});
		IPage<EquipmentCategory> page;
		if (StringUtils.isBlank(pageNum) || StringUtils.isBlank(pageSize)) {
			pageBean = new Page<>(0, Long.MAX_VALUE);
		} else {
			pageBean = new Page<>(Integer.parseInt(pageNum), Integer.parseInt(pageSize));
		}
		page = iEquipmentCategoryService.page(pageBean, equipmentCategoryQueryWrapper);
		return page;
	}

	/**
	 * 全量数据树形结构返回
	 * 
	 * @return
	 */
	@RequestMapping(value = "/list-tree", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "全量数据树形结构返回", notes = "全量数据树形结构返回")
	public List<EquipmentCategory> list() {
		List<EquipmentCategory> equipmentCategorys = this.iEquipmentCategoryService
				.getEquipmentCategoryList(Integer.valueOf(equipmentCategoryLeftTypeCode));
		List<EquipmentCategory> list = new ArrayList<>();
		Map<String, List<EquipmentCategory>> tmpMap = new HashMap<String, List<EquipmentCategory>>();
		equipmentCategorys.forEach(action -> {
			if (action.getParentId() == null) {
				list.add(action);
			} else {
				if (tmpMap.get(action.getParentId().toString()) == null) {
					ArrayList<EquipmentCategory> tmplist = new ArrayList<EquipmentCategory>();
					tmplist.add(action);
					tmpMap.put(action.getParentId().toString(), tmplist);
				} else {
					if (!tmpMap.get(action.getParentId().toString()).contains(action)) {
						tmpMap.get(action.getParentId().toString()).add(action);
					}
				}
			}
		});
		getChildren(list, tmpMap);
		return list;
	}


	/**
	 * 除消防设施全量数据树形结构返回
	 *
	 * @return
	 */
	@RequestMapping(value = "/equip-tree", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "除消防设施全量数据树形结构返回", notes = "除消防设施全量数据树形结构返回")
	public List<EquipmentCategory> listEquip() {
		List<EquipmentCategory> equipmentCategorys = this.iEquipmentCategoryService
				.getEquipmentCategoryListNotFacilities(Integer.valueOf(equipmentCategoryLeftTypeCode));
		List<EquipmentCategory> list = new ArrayList<>();
		Map<String, List<EquipmentCategory>> tmpMap = new HashMap<String, List<EquipmentCategory>>();
		equipmentCategorys.forEach(action -> {
			if (action.getParentId() == null) {
				list.add(action);
			} else {
				if (tmpMap.get(action.getParentId().toString()) == null) {
					ArrayList<EquipmentCategory> tmplist = new ArrayList<EquipmentCategory>();
					tmplist.add(action);
					tmpMap.put(action.getParentId().toString(), tmplist);
				} else {
					if (!tmpMap.get(action.getParentId().toString()).contains(action)) {
						tmpMap.get(action.getParentId().toString()).add(action);
					}
				}
			}
		});
		getChildren(list, tmpMap);
		return list;
	}

	/**
	 * 消防设施分类定义树
	 *
	 * @return
	 */
	@RequestMapping(value = "/list-tree-fire", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "消防设施分类定义树", notes = "消防设施分类定义树")
	public List<EquipmentCategory> listFire() {
		List<EquipmentCategory> equipmentCategorys = this.iEquipmentCategoryService
				.getEquipmentCategoryListByFacilities(Integer.valueOf(equipmentCategoryLeftTypeCode));
		List<EquipmentCategory> list = new ArrayList<>();
		Map<String, List<EquipmentCategory>> tmpMap = new HashMap<String, List<EquipmentCategory>>();
		equipmentCategorys.forEach(action -> {
			if (action.getName().equals("消防设施")) {
				list.add(action);
			} else {
				if (tmpMap.get(action.getParentId().toString()) == null) {
					ArrayList<EquipmentCategory> tmplist = new ArrayList<EquipmentCategory>();
					tmplist.add(action);
					tmpMap.put(action.getParentId().toString(), tmplist);
				} else {
					if (!tmpMap.get(action.getParentId().toString()).contains(action)) {
						tmpMap.get(action.getParentId().toString()).add(action);
					}
				}
			}
		});
		getChildren(list, tmpMap);
		return list;
	}

	/**
	 * 
	 * 获取子节点
	 **/
	private void getChildren(List<EquipmentCategory> list, Map<String, List<EquipmentCategory>> tmpMap) {
		for (EquipmentCategory equipmentCategory : list) {
			if (tmpMap.get(equipmentCategory.getId().toString()) != null
					&& tmpMap.get(equipmentCategory.getId().toString()).size() > 0) {
				List<EquipmentCategory> equipcliss = tmpMap.get(equipmentCategory.getId().toString());
				equipmentCategory.setHasLowerClassification(true);
				equipmentCategory.setChildren(equipcliss);
				getChildren(equipcliss, tmpMap);
			}
		}
	}

	/**
	 * 全量数据树形结构返回
	 * 
	 * @return
	 */
	@RequestMapping(value = "/tree/{type}", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "数据树形结构返回", notes = "数据树形结构返回")
	public List<EquipmentCategory> tree(@PathVariable String type) {
		return iEquipmentCategoryService.tree(type);
	}

	/**
	 * 首页数据统计（装备分类统计）
	 *
	 * @return
	 */
	@GetMapping(value = "/typeCount")
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "首页数据统计（装备分类统计）", notes = "首页数据统计")
	public List<EquipmentCategoryCountVO> typeCount() {
		return iEquipmentCategoryService.typeCount();
	}

	/**
	 * 首页数据统计（装备类型下拉框）
	 *
	 * @return
	 */
	@GetMapping(value = "/getTypeTree")
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "首页数据统计（装备类型下拉框）", notes = "装备类型下拉框")
	public List<EquipmentCategoryTypeTreeVO> getTypeTree(Long id) {
		return iEquipmentCategoryService.getTypeTree(id);
	}

	/**
	 * 装备列表
	 *
	 * @return
	 */
	@GetMapping(value = "/getEquipTypeAmount")
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "首页装备列表", notes = "装备信息列表")
	public List<EquipTypeAmountVO> getEquipTypeAmount(EquipTypeAmountDTO equipTypeAmountDTO) {
		IPage<EquipmentCategory> page = new Page();
		page.setCurrent(equipTypeAmountDTO.getCurrent());
		page.setSize(equipTypeAmountDTO.getPageSize());
		return iEquipmentCategoryService.CategoryAmountList(page, equipTypeAmountDTO.getHierarchy(),
				equipTypeAmountDTO.getEquipmentClassificationCode().substring(0, equipTypeAmountDTO.getHierarchy()),
				equipTypeAmountDTO.getEquipmentName());
	}

	@RequestMapping(value = "/checkFather", method = RequestMethod.POST)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "POST", value = "新增装备分类", notes = "新增装备分类")
	public String checkFather(HttpServletRequest request, @RequestBody List<String> ids) {
		return iEquipmentCategoryService.checkFather(ids);
	}

	/**
	 * 全量数据树形结构返回
	 *
	 * @return
	 */
	@RequestMapping(value = "/cola/list-tree", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "全量数据树形结构返回", notes = "全量数据树形结构返回")
	public List<IndustryVo> treeList() {
		List<IndustryVo> result = new ArrayList<>();
		// 判断缓存中是否有该数据
		boolean treeListFlag = redisUtils.hasKey(equipmentTreeListAll);
		if (treeListFlag) {
			if (redisUtils.get(equipmentTreeListAll) != null) {
				result = JSONObject.parseArray(redisUtils.get(equipmentTreeListAll).toString(), IndustryVo.class);
			}
		} else {
			// 缓存中没有, 读取并写入缓存
			result = getTreeList();
			redisUtils.set(equipmentTreeListAll, JSONObject.toJSONString(result), 0);
		}
		return result;
	}

	/**
	 * 数据库读取装备树
	 * 
	 * @return
	 */
	public List<IndustryVo> getTreeList() {
		List<IndustryVo> result = this.iEquipmentCategoryService.getTreeListAll();
		return result;
	}

	/**
	 * 根据行业过滤树形结构返回
	 *
	 * @return
	 */

	@RequestMapping(value = "/cola/industry-tree", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "根据行业过滤树形结构返回", notes = "根据行业过滤树形结构返回")
	public List<EquipmentCategory> industryTreeList(@RequestParam String code) {
		List<EquipmentCategory> list = new ArrayList<>();
		if (!"".equals(code)) {
			// 判断缓存中是否有该数据
			String equipmentTreeListIndustryKey = equipmentTreeListIndustry + "-" + code;
			boolean treeListFlag = redisUtils.hasKey(equipmentTreeListIndustryKey);
			if (treeListFlag) {
				if (redisUtils.get(equipmentTreeListIndustryKey) != null) {
					list = JSONObject.parseArray(redisUtils.get(equipmentTreeListIndustryKey).toString(),
							EquipmentCategory.class);
				}
			} else {
				// 缓存中没有, 读取并写入缓存
				list = getIndustryTreeList(code);
				redisUtils.set(equipmentTreeListIndustryKey, JSONObject.toJSONString(list), 0);
			}
		}
		return list;
	}

	@RequestMapping(value = "/cola/industry-tree/CarOrEqu", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "根据行业过滤树形结构返回", notes = "根据行业过滤树形结构返回")
	public List<EquipmentCategory> industryTreeList(@RequestParam String code,@RequestParam String codedate) {
		List<EquipmentCategory> list = new ArrayList<>();
		if (!"".equals(code)) {
			// 判断缓存中是否有该数据
			String equipmentTreeListIndustryKey = equipmentTreeListIndustry + "-" + code+ "-" + codedate;
			boolean treeListFlag = redisUtils.hasKey(equipmentTreeListIndustryKey);
			if (!treeListFlag) {
				if (redisUtils.get(equipmentTreeListIndustryKey) != null) {
					list = JSONObject.parseArray(redisUtils.get(equipmentTreeListIndustryKey).toString(),
							EquipmentCategory.class);
				}
			} else {
				// 缓存中没有, 读取并写入缓存
				list = getIndustryTreeListCarOrEqu(code,codedate);
				redisUtils.set(equipmentTreeListIndustryKey, JSONObject.toJSONString(list), 0);
			}
		}
		return list;
	}



	public List<EquipmentCategory> getIndustryTreeList(String code) {
		List<EquipmentCategory> list = this.iEquipmentCategoryService.getIndustryTreeList(code);
		return list;
	}

	public List<EquipmentCategory> getIndustryTreeListCarOrEqu(String code,String codedate) {
		List<EquipmentCategory> list = this.iEquipmentCategoryService.getColaEquipmentCategoryListCarOrEqu(code,codedate);
		return list;
	}
	/**
	 *
	 * 获取子节点
	 */
	private void getChildrenList(List<EquipmentCategory> list, Map<String, List<EquipmentCategory>> tmpMap) {
		for (EquipmentCategory equipmentCategory : list) {
			if (tmpMap.get(equipmentCategory.getId().toString()) != null
					&& tmpMap.get(equipmentCategory.getId().toString()).size() > 0) {
				List<EquipmentCategory> equipcliss = tmpMap.get(equipmentCategory.getId().toString());
				equipmentCategory.setHasLowerClassification(true);
				equipmentCategory.setChildren(equipcliss);
				getChildrenList(equipcliss, tmpMap);
			}
		}
	}

	/**
	 * 根据key删除缓存
	 *
	 * @return
	 */
	@RequestMapping(value = "/deleteEquipmentTreeCache", method = RequestMethod.GET)
	@TycloudOperation(ApiLevel = UserType.AGENCY)
	@ApiOperation(httpMethod = "GET", value = "删除装备树缓存", notes = "删除装备树缓存数据")
	public void deleteEquipmentTreeCache() {
		// 根据缓存key前缀删除装备相关缓存
		Set<String> keys = redisUtils.getKeys(prefix);
		if (keys != null && keys.size() > 0) {
			for (String key : keys) {
				redisUtils.del(key);
			}
		}
	}

}
