package com.njcn.supervision.service.user.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.bpm.api.BpmProcessFeignClient;
import com.njcn.bpm.enums.BpmProcessInstanceStatusEnum;
import com.njcn.bpm.enums.BpmTaskStatusEnum;
import com.njcn.bpm.pojo.dto.BpmInstanceInfo;
import com.njcn.bpm.pojo.dto.BpmProcessInstanceCreateReqDTO;
import com.njcn.bpm.pojo.param.instance.BpmProcessInstanceCancelParam;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.supervision.enums.SupervisionKeyEnum;
import com.njcn.supervision.enums.UserNatureEnum;
import com.njcn.supervision.mapper.user.UserReportNormalMapper;
import com.njcn.supervision.pojo.param.user.UserReportNormalParam;
import com.njcn.supervision.pojo.po.user.*;
import com.njcn.supervision.pojo.vo.user.NewUserReportVO;
import com.njcn.supervision.pojo.vo.user.UserReportVO;
import com.njcn.supervision.service.user.*;
import com.njcn.supervision.utils.InstanceUtil;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.vo.UserVO;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 干扰源用户常态化管理 服务实现类
 * </p>
 *
 * @author hongawen
 * @since 2024-05-17
 */
@Service
@RequiredArgsConstructor
public class UserReportNormalServiceImpl extends ServiceImpl<UserReportNormalMapper, UserReportNormalPO> implements IUserReportNormalService {


    private final BpmProcessFeignClient bpmProcessFeignClient;
    private final UserReportProjectPOService userReportProjectPOService;
    private final UserReportSubstationPOService userReportSubstationPOService;
    private final UserReportSensitivePOService userReportSensitivePOService;
    private final UserReportPOService userReportPOService;
    private final UserFeignClient userFeignClient;
    private final DeptFeignClient deptFeignClient;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addUserNormal(UserReportNormalParam userReportNormalParam) {
        UserReportNormalPO userReportNormalPO = new UserReportNormalPO();
        BeanUtil.copyProperties(userReportNormalParam, userReportNormalPO);
        userReportNormalPO.setState(DataStateEnum.ENABLE.getCode());
        if (Objects.equals(userReportNormalParam.getSaveOrCheckflag(), "1")) {
            userReportNormalPO.setStatus(BpmTaskStatusEnum.WAIT.getStatus());
        } else {
            userReportNormalPO.setStatus(BpmTaskStatusEnum.RUNNING.getStatus());

        }
        userReportNormalPO.setCreateBy(RequestUtil.getUserIndex());
        this.saveOrUpdate(userReportNormalPO);
        userReportNormalPO = this.getById(userReportNormalPO.getId());
        if (Objects.equals(userReportNormalParam.getSaveOrCheckflag(), "2")) {
            // 发起 BPM 流程
            Map<String, Object> processInstanceVariables = new HashMap<>(16);
            BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
            if (0 == userReportNormalParam.getType()) {
                bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(SupervisionKeyEnum.USER_GO_NET.getKey());
            } else {
                bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(SupervisionKeyEnum.USER_TREAT_CHECK.getKey());
            }
            bpmProcessInstanceCreateReqDTO.setBusinessKey(userReportNormalPO.getId());
            bpmProcessInstanceCreateReqDTO.setStartUserSelectAssignees(userReportNormalParam.getStartUserSelectAssignees());
            bpmProcessInstanceCreateReqDTO.setVariables(processInstanceVariables);
            String processInstanceId = bpmProcessFeignClient.createProcessInstance(userReportNormalPO.getCreateBy(), bpmProcessInstanceCreateReqDTO).getData();
            // 将工作流的编号，更新到流程单中
            userReportNormalPO.setProcessInstanceId(processInstanceId);
            this.baseMapper.updateById(userReportNormalPO);
        }

        return userReportNormalPO.getId();
    }

    @Override
    public String updateUserNormal(UserReportNormalParam userReportParam) {
        UserReportNormalPO userReportNormalPO = this.baseMapper.selectById(userReportParam.getId());
        //判断是否有权限操作
        InstanceUtil.judgeUserPower(RequestUtil.getUserIndex(), userReportNormalPO.getCreateBy());
        //处理历史流程id列表
        String historyInstanceIds = InstanceUtil.dealHistoryId(userReportNormalPO.getProcessInstanceId(), userReportNormalPO.getHistoryInstanceId());
        BeanUtils.copyProperties(userReportParam, userReportNormalPO);
        userReportNormalPO.setState(DataStateEnum.ENABLE.getCode());
        userReportNormalPO.setStatus(BpmTaskStatusEnum.RUNNING.getStatus());
        // 发起 BPM 流程
        Map<String, Object> processInstanceVariables = new HashMap<>(16);
        BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
        if (userReportNormalPO.getType() == 0) {
            bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(SupervisionKeyEnum.USER_GO_NET.getKey());
        } else {
            bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(SupervisionKeyEnum.USER_TREAT_CHECK.getKey());
        }
        bpmProcessInstanceCreateReqDTO.setBusinessKey(userReportNormalPO.getId());
        bpmProcessInstanceCreateReqDTO.setStartUserSelectAssignees(userReportParam.getStartUserSelectAssignees());
        bpmProcessInstanceCreateReqDTO.setVariables(processInstanceVariables);
        String processInstanceId = bpmProcessFeignClient.createProcessInstance(userReportNormalPO.getCreateBy(), bpmProcessInstanceCreateReqDTO).getData();
        // 将工作流的编号，更新到流程单中
        userReportNormalPO.setProcessInstanceId(processInstanceId);
        //保存历史流程id列表
        userReportNormalPO.setHistoryInstanceId(historyInstanceIds);
        this.baseMapper.updateById(userReportNormalPO);
        return userReportNormalPO.getId();
    }

    @Override
    public Page<UserReportVO.UserReportGoNetVO> userReportGoNetPage(UserReportNormalParam userReportNormalParam) {
        Page<UserReportVO.UserReportGoNetVO> pageResult = new Page<>();
        List<String> colleaguesIds = userFeignClient.getColleaguesIdByUserId(RequestUtil.getUserIndex()).getData();
        if (CollUtil.isEmpty(colleaguesIds)) {
            return pageResult;
        }
        LambdaQueryWrapper<UserReportNormalPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByDesc(UserReportNormalPO::getCreateTime)
                .eq(UserReportNormalPO::getType, userReportNormalParam.getType())
                .in(UserReportNormalPO::getCreateBy, colleaguesIds)
                .eq(UserReportNormalPO::getUserReportId, userReportNormalParam.getUserReportId()).eq(Objects.nonNull(userReportNormalParam.getStatus()), UserReportNormalPO::getStatus, userReportNormalParam.getStatus());

        Page<UserReportNormalPO> page = this.page(new Page<>(PageFactory.getPageNum(userReportNormalParam), PageFactory.getPageSize(userReportNormalParam)), lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            List<String> ids = page.getRecords().stream().map(UserReportNormalPO::getUserReportId).distinct().collect(Collectors.toList());
            List<UserReportPO> userReportPOList = userReportPOService.list(new LambdaQueryWrapper<UserReportPO>().in(UserReportPO::getId, ids));
            Map<String, UserReportPO> map = userReportPOList.stream().collect(Collectors.toMap(UserReportPO::getId, Function.identity()));

            List<UserReportVO.UserReportGoNetVO> temList = new ArrayList<>();
            page.getRecords().forEach(item -> {
                UserReportVO.UserReportGoNetVO vo = new UserReportVO.UserReportGoNetVO();
                UserReportPO userReportPO = map.get(item.getUserReportId());
                BeanUtil.copyProperties(userReportPO, vo);
                vo.setId(item.getId());
                vo.setUserReportId(item.getUserReportId());
                vo.setOtherReport(item.getReportUrl());
                vo.setSimulationReport(item.getSimulationReportUrl());
                vo.setProcessInstanceId(item.getProcessInstanceId());
                vo.setCreateTime(item.getCreateTime());
                vo.setStatus(item.getStatus());
                vo.setReporter(item.getCreateBy());
                temList.add(vo);
            });
            BeanUtil.copyProperties(page, pageResult);
            pageResult.setRecords(temList);
        }
        return pageResult;
    }

    @Override
    public UserReportVO.UserReportGoNetVO userReportGoNetById(String id) {
        UserReportNormalPO userReportNormalPO = this.getById(id);
        if (Objects.nonNull(userReportNormalPO)) {
            UserReportPO userReportPO = userReportPOService.getById(userReportNormalPO.getUserReportId());
            UserReportVO.UserReportGoNetVO vo = new UserReportVO.UserReportGoNetVO();
            BeanUtil.copyProperties(userReportPO, vo);
            BeanUtil.copyProperties(userReportNormalPO, vo);
            vo.setOtherReport(userReportNormalPO.getReportUrl());
            vo.setSimulationReport(userReportNormalPO.getSimulationReportUrl());
            return vo;
        }
        return null;
    }

    @Override
    public void updateProcessStatus(String businessKey, Integer status) {
        this.update(new UpdateWrapper<UserReportNormalPO>().lambda().set(UserReportNormalPO::getStatus, status).eq(UserReportNormalPO::getId, businessKey));
    }

    @Override
    public BpmInstanceInfo getInstanceInfo(String businessId) {
        BpmInstanceInfo bpmInstanceInfo = new BpmInstanceInfo();
        UserReportVO.UserReportGoNetVO userReportGoNet = this.userReportGoNetById(businessId);
        if (Objects.nonNull(userReportGoNet)) {
            bpmInstanceInfo.setHistoryInstanceId(userReportGoNet.getHistoryInstanceId());
            bpmInstanceInfo.setInstanceSign(userReportGoNet.getProjectName());
            return bpmInstanceInfo;
        }
        return null;
    }


    @Override
    public Set<String> getAllRejectInstanceIds() {
        Set<String> rejectInstanceIds = new HashSet<>();
        //查询当前用户创建的createBy的流程审核不通过的
        LambdaQueryWrapper<UserReportNormalPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserReportNormalPO::getCreateBy, RequestUtil.getUserIndex())
                .eq(UserReportNormalPO::getStatus, BpmProcessInstanceStatusEnum.REJECT.getStatus())
                .eq(UserReportNormalPO::getState, DataStateEnum.ENABLE.getCode())
                .select(UserReportNormalPO::getProcessInstanceId);
        List<UserReportNormalPO> userReportNormalPOList = this.baseMapper.selectList(lambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(userReportNormalPOList)) {
            List<String> result = userReportNormalPOList.stream().map(UserReportNormalPO::getProcessInstanceId).collect(Collectors.toList());
            rejectInstanceIds.addAll(result);
        }
        return rejectInstanceIds;
    }

    @Override
    public String cancelUserReport(BpmProcessInstanceCancelParam cancelReqVO) {
        //准备取消该流程，需要远程调用接口
        UserReportNormalPO userReportNormalPO = this.baseMapper.selectById(cancelReqVO.getId());
        //判断是否有权限操作
        InstanceUtil.judgeUserPower(RequestUtil.getUserIndex(), userReportNormalPO.getCreateBy());
        //取消流程
        bpmProcessFeignClient.cancelProcessInstanceByStartUser(cancelReqVO);
        //更新状态
        userReportNormalPO.setStatus(BpmProcessInstanceStatusEnum.CANCEL.getStatus());
        this.updateById(userReportNormalPO);
        return userReportNormalPO.getId();
    }

    @Override
    public UserReportVO.UserReportListVO getUserReportByFangAnId(String id) {
        UserReportNormalPO userReportNormalServiceById = this.getById(id);
        UserReportVO.UserReportListVO userReportVO = new UserReportVO.UserReportListVO();
        UserReportPO userReportPO = userReportPOService.getById(userReportNormalServiceById.getUserReportId());
        //复制基础信息
        BeanUtil.copyProperties(userReportPO, userReportVO);
        //处理特殊字段，用户名、部门名
        UserVO userVO = userFeignClient.getUserById(userReportPO.getReporter()).getData();
        userReportVO.setReporter(userVO.getName());
        userReportVO.setOrgName(deptFeignClient.getDeptById(userReportPO.getOrgId()).getData().getName());
        /*
            根据用户性质获取自己特有的字段，此处需要特殊处理
            1、每个附件需要返回文件名称以及可以预览的url
            todo...by黄正剑
         */
        if (
                CollectionUtil.newArrayList(
                        UserNatureEnum.BUILD_POWER_GRID.getCode(),
                        UserNatureEnum.EXTEND_POWER_GRID.getCode()
                ).contains(userReportPO.getUserType())) {
            //电网工程类用户额外数据
            UserReportProjectPO byId = userReportProjectPOService.getById(userReportNormalServiceById.getUserReportId());
            userReportVO.setUserReportProjectPO(byId);

        } else if (
                CollectionUtil.newArrayList(
                        UserNatureEnum.BUILD_NON_LINEAR_LOAD.getCode(),
                        UserNatureEnum.EXTEND_NON_LINEAR_LOAD.getCode(),
                        UserNatureEnum.BUILD_NEW_ENERGY_POWER_STATION.getCode(),
                        UserNatureEnum.EXTEND_NEW_ENERGY_POWER_STATION.getCode()
                ).contains(userReportPO.getUserType())) {
            //非线性负荷用户 & 新能源发电站用户
            UserReportSubstationPO byId = userReportSubstationPOService.getById(userReportNormalServiceById.getUserReportId());
            userReportSubstationPOService.saveOrUpdate(byId);
            userReportVO.setUserReportSubstationPO(byId);
        } else if (UserNatureEnum.SENSITIVE_USER.getCode().equals(userReportPO.getUserType())) {
            // 敏感及重要用户
            UserReportSensitivePO byId = userReportSensitivePOService.getById(userReportNormalServiceById.getUserReportId());
            userReportVO.setUserReportSensitivePO(byId);
        }
        List<UserReportNormalPO> list = this.baseMapper.selectList(new LambdaQueryWrapper<UserReportNormalPO>()
                .eq(UserReportNormalPO::getUserReportId, userReportNormalServiceById.getUserReportId())
                .eq(UserReportNormalPO::getStatus, BpmTaskStatusEnum.APPROVE.getStatus())
                .eq(UserReportNormalPO::getState, DataStateEnum.ENABLE.getCode())
                .orderByDesc(UserReportNormalPO::getCreateTime)
        );
        Optional<String> netInReport = list.stream().filter(x -> 0 == x.getType()).map(UserReportNormalPO::getReportUrl).findFirst();
        Optional<String> governReport = list.stream().filter(x -> 1 == x.getType()).map(UserReportNormalPO::getReportUrl).findFirst();
        Optional<String> simulationReport = list.stream().filter(x -> 1 == x.getType()).map(UserReportNormalPO::getSimulationReportUrl).findFirst();
        userReportVO.setNetInReport(Collections.singletonList(netInReport.orElse(null)));
        userReportVO.setGovernReport(Collections.singletonList(governReport.orElse(null)));
        userReportVO.setSimulationReport(Collections.singletonList(simulationReport.orElse(null)));
        return userReportVO;
    }

    @Override
    public List<NewUserReportVO> getUserReportByIds(List<String> ids) {
        List<UserReportPO> userReportPOS = userReportPOService.listByIds(ids);
        List<NewUserReportVO> info = new ArrayList<>();
        for (UserReportPO userReportNormalPO : userReportPOS) {
            NewUserReportVO newUserReportVO = new NewUserReportVO();
            BeanUtil.copyProperties(userReportNormalPO, newUserReportVO);
            info.add(newUserReportVO);
        }
        return info;
    }
}
