package com.yeejoin.amos.supervision.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.excel.DataSources;
import com.yeejoin.amos.boot.biz.common.excel.ExcelUtil;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.supervision.business.dao.mapper.HiddenDangerMapper;
import com.yeejoin.amos.supervision.business.dao.repository.ICheckInputDao;
import com.yeejoin.amos.supervision.business.dao.repository.ICheckShotDao;
import com.yeejoin.amos.supervision.business.dao.repository.IHiddenDangerDao;
import com.yeejoin.amos.supervision.business.dao.repository.IPlanDao;
import com.yeejoin.amos.supervision.business.dao.repository.IPointDao;
import com.yeejoin.amos.supervision.business.dto.HiddenDangerDto;
import com.yeejoin.amos.supervision.business.dto.HiddenDangerExportDataDto;
import com.yeejoin.amos.supervision.business.dto.HiddenDangerImportDto;
import com.yeejoin.amos.supervision.business.dto.HiddenDangerTemplateDto;
import com.yeejoin.amos.supervision.business.feign.DangerFeignClient;
import com.yeejoin.amos.supervision.business.feign.JCSFeignClient;
import com.yeejoin.amos.supervision.business.service.intfc.IHiddenDangerService;
import com.yeejoin.amos.supervision.common.enums.CheckTypeSuEnum;
import com.yeejoin.amos.supervision.common.enums.DangerCheckTypeLevelEnum;
import com.yeejoin.amos.supervision.common.enums.DangerHandleTypeEnum;
import com.yeejoin.amos.supervision.core.common.dto.DangerDto;
import com.yeejoin.amos.supervision.dao.entity.CheckInput;
import com.yeejoin.amos.supervision.dao.entity.CheckShot;
import com.yeejoin.amos.supervision.dao.entity.HiddenDanger;
import com.yeejoin.amos.supervision.dao.entity.Plan;
import com.yeejoin.amos.supervision.dao.entity.Point;
import lombok.extern.slf4j.Slf4j;
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.StringUtils;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.DateUtil;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.DataNotFound;

import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author DELL
 */
@Service
@Slf4j
public class HiddenDangerServiceImpl implements IHiddenDangerService {

    @Autowired
    DangerFeignClient feignClient;

    @Autowired
    IHiddenDangerDao iHiddenDangerDao;

    @Autowired
    HiddenDangerMapper hiddenDangerMapper;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    Sequence sequence;

    @Autowired
    DataSources dataSources;

    @Autowired
    IPlanDao iPlanDao;

    @Autowired
    ICheckInputDao iCheckInputDao;

    @Autowired
    ICheckShotDao iCheckShotDao;

    @Autowired
    IPointDao iPointDao;

    @Autowired
    JCSFeignClient jcsFeignClient;

    @Override
    public List<HiddenDangerExportDataDto> listAll(String planId, Long pointId, String level, String status) {
        //1.查询指定计划和公司的关联隐患数据
        List<HiddenDangerDto> hiddenDangers = hiddenDangerMapper.listByCondition(planId, pointId);
        List<Long> dangerIds = Lists.transform(hiddenDangers, HiddenDangerDto::getLatentDangerId);
        String dangerIdsStr = "".equals(Joiner.on(",").join(dangerIds)) ? "-1" : Joiner.on(",").join(dangerIds);
        //2.调用隐患模块查询关联隐患的具体数据（业务系统直落关系，具体隐患数据再隐患服务进行储存）
        Map<String, Object> param = new HashMap<>();
        param.put("dangerIds", dangerIdsStr);
        param.put("dangerLevel", level);
        param.put("dangerState", status);
        FeignClientResult<List<DangerDto>> daResult = feignClient.listAll(param);
        List<DangerDto> allData = daResult.getResult();
        Map<Long, HiddenDangerDto> keyMap = hiddenDangers.stream().collect(Collectors.toMap(HiddenDangerDto::getLatentDangerId, Function.identity()));
        //3.将查询会来的数据与业务数据拼接，进行返回
        return allData.stream().map(s -> {
            HiddenDangerExportDataDto exportDto = new HiddenDangerExportDataDto();
            Bean.copyExistPropertis(s, exportDto);
            HiddenDangerDto hiddenDangerDto = keyMap.get(s.getId());
            exportDto.setCheckTime(hiddenDangerDto != null ? hiddenDangerDto.getCheckTime() : "");
            exportDto.setCheckUserName(hiddenDangerDto != null ? hiddenDangerDto.getCheckUserName() : "");
            exportDto.setPointName(hiddenDangerDto != null ? hiddenDangerDto.getPointName() : "");
            exportDto.setInputItemName(hiddenDangerDto != null ? hiddenDangerDto.getInputItemName() : "");
            exportDto.setDangerTypeName(hiddenDangerDto != null ? hiddenDangerDto.getDangerTypeName() : "");
            return exportDto;
        }).collect(Collectors.toList());
    }

    @Override
    public DangerDto getOne(Long latentDangerId) {
        HiddenDanger hiddenDanger = iHiddenDangerDao.findByLatentDangerId(latentDangerId);
        if (hiddenDanger == null) {
            throw new DataNotFound("该隐患数据不存在");
        }
        FeignClientResult<DangerDto> feignClientResult = feignClient.getOne(latentDangerId);
        return feignClientResult.getResult();
    }

    @Override
    public DangerDto updateDanger(Long latentDangerId, DangerDto dangerDto) throws Exception {
        HiddenDanger hiddenDanger = iHiddenDangerDao.findByLatentDangerId(latentDangerId);
        if (hiddenDanger == null) {
            throw new DataNotFound("该隐患数据不存在");
        }
        //组织业务数据，字段为bizInfo
        HiddenDangerDto hiddenDangerDto = new HiddenDangerDto();
        Bean.copyExistPropertis(hiddenDanger, hiddenDangerDto);
        Map<String, Object> bizInfo = this.buildBizInfo(hiddenDangerDto);
        dangerDto.setBizInfo(JSON.parseObject(JSON.toJSONString(bizInfo)));
        //feign 调用保存
        FeignClientResult<List<DangerDto>> feignClientResult = feignClient.saveOrUpdateBatch(Collections.singletonList(dangerDto),"3");
        //更新隐患
        List<DangerDto> saveDangers = feignClientResult.getResult();
        if (!saveDangers.isEmpty()) {
            hiddenDanger.setUpdateDate(new Date());
            iHiddenDangerDao.save(hiddenDanger);
            return saveDangers.get(0);
        } else {
            throw new RuntimeException("更新失败");
        }
    }

    @Override
    public IPage pageList(Page page, String planId, Long pointId, String level, String status) {
        List<HiddenDangerDto> dangers = hiddenDangerMapper.listByCondition(planId, pointId);
        List<Long> dangerIds = Lists.transform(dangers, HiddenDangerDto::getLatentDangerId);
        String dangerIdsStr = "".equals(Joiner.on(",").join(dangerIds)) ? "-1" : Joiner.on(",").join(dangerIds);
        Map<String, Object> param = buildRequestBody(page, level, status, dangerIdsStr);
        //可以获取导入的隐患列表信息，不加入instanceId 的判断,因为这个接口调用了隐患列表，需要一个参数判断是否有使用 --- by 陈浩 2022-04-14 --start
        param.put("isDraft", 1);
        FeignClientResult<Page<DangerDto>> feignClientResult = feignClient.pageList(param);
        param.remove("isDraft");
        //可以获取导入的隐患列表信息，不加入instanceId 的判断,因为这个接口调用了隐患列表，需要一个参数判断是否有使用 --- by 陈浩 2022-04-14 --end
        Page<DangerDto> dangerDtoIPage = feignClientResult.getResult();
        Map<Long, HiddenDangerDto> keyMap = dangers.stream().collect(Collectors.toMap(HiddenDangerDto::getLatentDangerId, Function.identity()));
        dangerDtoIPage.getRecords().forEach(r -> {
            HiddenDangerDto hiddenDangerDto = keyMap.get(r.getId());
            r.setCheckTime(hiddenDangerDto != null ? hiddenDangerDto.getCheckTime() : "");
            r.setCheckUserName(hiddenDangerDto != null ? hiddenDangerDto.getCheckUserName() : "");
            r.setPointName(hiddenDangerDto != null ? hiddenDangerDto.getPointName() : "");
            r.setInputItemName(hiddenDangerDto != null ? hiddenDangerDto.getInputItemName() : "");
            r.setDangerTypeName(hiddenDangerDto != null ? hiddenDangerDto.getDangerTypeName() : "");
            r.setDangerType(hiddenDangerDto != null ? hiddenDangerDto.getDangerType() : "");
            r.setReformLimitDate(DateUtils.longStr2Date(DateUtils.date2LongStr(r.getReformLimitDate())));
        });
        return dangerDtoIPage;
    }

    private Map<String, Object> buildRequestBody(Page page, String level, String status, String dangerIdsStr) {
        Map<String, Object> param = new HashMap<>();
        param.put("dangerIds", dangerIdsStr);
        param.put("dangerLevel", level);
        param.put("dangerState", status);
        param.put("current", page.getCurrent());
        param.put("size", page.getSize());
        return param;
    }

    @Override
    public void importDanger(ReginParams reginParams, Long planId, List<HiddenDangerImportDto> list) {
        //1.调用创建隐患
        ReginParams.PersonIdentity personIdentity = reginParams.getPersonIdentity();
        List<DangerDto> dtoList = list.stream().map(s -> {
            Long seq = sequence.nextId();
            String[] dangerArray = s.getDangerLevelName().split("@");
            String[] reformTypeArray = s.getReformTypeName().split("@");
            String[] pointArray = s.getPointName().split("@");
            DangerDto dangerDto = new DangerDto();
            Bean.copyExistPropertis(s, dangerDto);
            dangerDto.setBizType(contextPath.substring(1));
            dangerDto.setBizId(seq);
            dangerDto.setDangerLevel(dangerArray.length > 1 ? dangerArray[1] : "");
            dangerDto.setDangerLevelName(dangerArray.length > 1 ? dangerArray[0] : "");
            dangerDto.setReformType(reformTypeArray.length > 1 ? reformTypeArray[1] : "");
            dangerDto.setReformTypeName(reformTypeArray.length > 1 ? reformTypeArray[0] : "");
            //导入的为自行检查
            dangerDto.setCheckMode(DangerHandleTypeEnum.SELF.getCode());
            //组织业务基本数据 对应bizInfo
            HiddenDangerDto hiddenDangerDto = new HiddenDangerDto();
            hiddenDangerDto.setPlanId(planId);
            hiddenDangerDto.setPointId(pointArray.length > 1 ? Long.parseLong(StringUtils.trimAllWhitespace(pointArray[1])) : null);
            hiddenDangerDto.setPointName(pointArray.length > 1 ? pointArray[0] : null);
            hiddenDangerDto.setCheckInputId(seq);
            hiddenDangerDto.setDangerType(DangerHandleTypeEnum.SELF.getCode());
            try {
                dangerDto.setBizInfo(this.buildBizInfo(hiddenDangerDto));
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new RuntimeException("组织数据失败!" + e.getMessage());
            }
            return dangerDto;
        }).collect(Collectors.toList());
        FeignClientResult<List<DangerDto>> feignClientResult = feignClient.saveOrUpdateBatch(dtoList,"0");
        List<DangerDto> dangerDbs = feignClientResult.getResult();
        //2.保存隐患关系表
        List<HiddenDanger> hiddenDangers = dangerDbs.stream().map(d -> {
            HiddenDanger hiddenDanger = new HiddenDanger();
            hiddenDanger.setCreateBy(personIdentity.getPersonSeq());
            hiddenDanger.setPlanId(planId);
            hiddenDanger.setLatentDangerId(d.getId());
            hiddenDanger.setCheckInputId(d.getBizId());
            hiddenDanger.setDangerType(DangerHandleTypeEnum.SELF.getCode());
            hiddenDanger.setDangerTypeName((DangerHandleTypeEnum.SELF.getName()));
            hiddenDanger.setCreateDate(new Date());
            return hiddenDanger;
        }).collect(Collectors.toList());
        for (int i = 0; i < hiddenDangers.size(); i++) {
            String[] pointArray = list.get(i).getPointName().split("@");
            hiddenDangers.get(i).setPointId(pointArray.length > 1 ? Long.parseLong(pointArray[1]) : null);
        }
        iHiddenDangerDao.saveAll(hiddenDangers);
    }

    @Override
    public void templateExport(HttpServletResponse response) {
        ExcelUtil.createTemplate(response, "隐患清单", "隐患清单", null, HiddenDangerTemplateDto.class, dataSources, true);
    }

    @Override
    public void exportDangerData(String planId, Long pointId, String level, String status, HttpServletResponse response) {
        String fileName = "隐患问题清单_" + System.currentTimeMillis();
        List<HiddenDangerExportDataDto> dtoList = this.listAll(planId, pointId, level, status);
        ExcelUtil.createTemplate(response, fileName, "隐患问题清单", dtoList, HiddenDangerExportDataDto.class, dataSources, false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteBatch(List<Long> ids) {
        List<HiddenDanger> hiddenDangers = iHiddenDangerDao.findByLatentDangerIdIn(ids);
        if (!hiddenDangers.isEmpty()) {
            //删除隐患模块数据
            feignClient.deleteDangerBatch(Joiner.on(",").join(ids));
            //删除业务数据
            iHiddenDangerDao.deleteAll(hiddenDangers);
            return true;
        }
        return false;
    }

    @Override
    public Map<String, Object> buildBizInfo(HiddenDangerDto hiddenDangerDto) throws Exception {
        Map<String, Object> result = new HashMap<>(32);
        Optional<Plan> op = iPlanDao.findById(hiddenDangerDto.getPlanId());
        Plan plan = op.orElseThrow((() -> new RuntimeException("计划不存在")));
        Point point = new Point();
        if (!ObjectUtils.isEmpty(hiddenDangerDto.getPointId())) {
            point = iPointDao.findById(hiddenDangerDto.getPointId()).orElseThrow(() -> new RuntimeException("单位不存在"));
        } else {
            throw new RuntimeException("单位不存在");
        }
        //检查级别
        DangerCheckTypeLevelEnum dangerCheckTypeLevelEnum = DangerCheckTypeLevelEnum.getEumByCode(plan.getCheckLevel());
        //检查类型
        CheckTypeSuEnum checkTypeSuEnum = CheckTypeSuEnum.getEumByCode(plan.getCheckTypeId());
        String branch = PlanServiceImpl.workFlowExcuteBranch(dangerCheckTypeLevelEnum.getCondition(), checkTypeSuEnum.getCondition());
        result.put("planType", branch);
        result.put("checkMode", hiddenDangerDto.getDangerType());
        result.put("planId", plan.getId());
        result.put("planName", plan.getName());
        result.put("pointId", point.getOriginalId());
        result.put("pointName", point.getName());
        result.put("bizId", hiddenDangerDto.getCheckInputId());
        result.put("bizName", hiddenDangerDto.getInputItemName());
        result.put("routeId", plan.getRouteId());
        result.put("checkUnitId", plan.getCheckUnitId()); // 检查人所在单位id逗号隔开
        result.put("checkUnitName", plan.getCheckUnitName());// 检查人所在单位名称逗号隔开
        result.put("leadPeopleId", plan.getLeadPeopleIds()); // 牵头人id
        result.put("leadPeopleName", plan.getLeadPeopleNames()); // 牵头人名称
        result.put("makerUserId", plan.getMakerUserId()); // 计划制定人id
        result.put("makerUserName", plan.getMakerUserName()); // 计划制定人名称
        result.put("userId", plan.getUserId()); // 检查参与人id
        result.put("userIdName", plan.getUserName()); // 检查参与人名称
        // 放入标识隐患是外部导入还是非外部,1为外部导入
        String isOuter = DangerCheckTypeLevelEnum.EXTERNAL.getCode().equals(plan.getCheckLevel()) ? "1" : "0";
        result.put("isOuter", isOuter);
        // 将机场单位bizOrgCode保存起来用于按机场单位数据过滤
        FeignClientResult<Map<String, Object>> companyResult = jcsFeignClient.getCompanyById(point.getOriginalId());
        if (!ValidationUtil.isEmpty(companyResult)) {
            result.put("bizOrgCode", companyResult.getResult().get("bizOrgCode"));
        }
        this.buildCheckInfo(result, hiddenDangerDto.getCheckInputId());
        return result;
    }

    private void buildCheckInfo(Map<String, Object> result, Long checkInputId) {
        CheckInput checkInput = iCheckInputDao.findById(checkInputId).orElse(null);
        if (checkInput == null) {
            return;
        }
        List<CheckShot> shotList = iCheckShotDao.findAllByCheckIdAndCheckInputId(checkInput.getCheckId(), checkInput.getId());
        result.put("checkUserId", checkInput.getUserId()); // 任务执行人id
        result.put("checkUserName", checkInput.getUserName()); // 任务执行人名称
        result.put("accompanyingUserId", checkInput.getAccompanyUserId()); // 检查陪同人id
        result.put("accompanyingUserName", checkInput.getAccompanyUserName()); // 检查陪同人名称
        result.put("planExecuteTime", checkInput.getCreateDate()); // 计划任务执行时间
        result.put("checkPhotoUrl", shotList.stream().map(CheckShot::getPhotoData).collect(Collectors.joining(",")));
    }
}
