package com.yunzhupaas.flowable.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.yunzhupaas.base.vo.ListVO;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.constant.PermissionConst;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.DelegateEntity;
import com.yunzhupaas.flowable.entity.DelegateInfoEntity;
import com.yunzhupaas.flowable.entity.TemplateEntity;
import com.yunzhupaas.flowable.entity.TemplateJsonEntity;
import com.yunzhupaas.flowable.mapper.DelegateMapper;
import com.yunzhupaas.flowable.model.candidates.CandidateUserVo;
import com.yunzhupaas.flowable.model.delegate.DelegateCrForm;
import com.yunzhupaas.flowable.model.delegate.DelegateListVO;
import com.yunzhupaas.flowable.model.delegate.DelegatePagination;
import com.yunzhupaas.flowable.model.delegate.DelegateUpForm;
import com.yunzhupaas.flowable.model.message.DelegateModel;
import com.yunzhupaas.flowable.model.template.TemplatePageLisVO;
import com.yunzhupaas.flowable.model.template.TemplatePagination;
import com.yunzhupaas.flowable.model.util.FlowConstant;
import com.yunzhupaas.flowable.model.util.FlowNature;
import com.yunzhupaas.flowable.service.DelegateInfoService;
import com.yunzhupaas.flowable.service.DelegateService;
import com.yunzhupaas.flowable.service.TemplateJsonService;
import com.yunzhupaas.flowable.service.TemplateService;
import com.yunzhupaas.flowable.util.MsgUtil;
import com.yunzhupaas.flowable.util.ServiceUtil;
import com.yunzhupaas.message.model.SentMessageForm;
import com.yunzhupaas.permission.entity.OrganizeEntity;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.permission.entity.UserRelationEntity;
import com.yunzhupaas.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

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

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/5/13 16:56
 */
@Service
public class DelegateServiceImpl extends SuperServiceImpl<DelegateMapper, DelegateEntity> implements DelegateService {
    @Autowired
    private TemplateService templateService;
    @Autowired
    private TemplateJsonService templateJsonService;
    @Lazy
    @Autowired
    private MsgUtil msgUtil;
    @Autowired
    private ServiceUtil serviceUtil;
    @Autowired
    private DelegateInfoService delegateInfoService;

    @Override
    public List<DelegateListVO> getList(DelegatePagination pagination) {
        String userId = UserProvider.getLoginUserId();
        String keyword = pagination.getKeyword();
        QueryWrapper<DelegateEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(DelegateEntity::getUserId, userId);

        QueryWrapper<DelegateInfoEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtil.isNotBlank(keyword)) {
            queryWrapper.lambda().like(DelegateInfoEntity::getToUserName, keyword);
        }
        List<DelegateInfoEntity> delegateInfoList = delegateInfoService.list(queryWrapper);
        List<String> delegateIds = delegateInfoList.stream().map(DelegateInfoEntity::getDelegateId).distinct()
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(delegateIds)) {
            if (StringUtil.isNotBlank(keyword)) {
                wrapper.lambda().and(
                        e -> e.in(DelegateEntity::getId, delegateIds).or().like(DelegateEntity::getFlowName, keyword));
            } else {
                wrapper.lambda().in(DelegateEntity::getId, delegateIds);
            }
        } else {
            if (StringUtil.isNotBlank(keyword)) {
                wrapper.lambda().like(DelegateEntity::getFlowName, keyword);
            } else {
                return new ArrayList<>();
            }
        }
        if (ObjectUtil.equals(pagination.getType(), 1)) {
            wrapper.lambda().eq(DelegateEntity::getType, 0);// 委托
        } else {
            wrapper.lambda().eq(DelegateEntity::getType, 1);// 代理
        }
        wrapper.lambda().orderByAsc(DelegateEntity::getSortCode).orderByDesc(DelegateEntity::getCreatorTime);
        Page<DelegateEntity> page = new Page<>(pagination.getCurrentPage(), pagination.getPageSize());
        IPage<DelegateEntity> iPage = this.page(page, wrapper);
        List<DelegateEntity> dataList = pagination.setData(iPage.getRecords(), page.getTotal());

        List<DelegateListVO> voList = new ArrayList<>();
        long time = new Date().getTime();
        List<String> ids = dataList.stream().map(DelegateEntity::getId).distinct().collect(Collectors.toList());
        List<DelegateInfoEntity> list = delegateInfoService.getList(ids);
        for (DelegateEntity delegate : dataList) {
            DelegateListVO vo = JsonUtil.getJsonToBean(delegate, DelegateListVO.class);
            List<DelegateInfoEntity> infoList = list.stream()
                    .filter(e -> ObjectUtil.equals(e.getDelegateId(), delegate.getId())).collect(Collectors.toList());
            List<String> toUserNameList = infoList.stream().map(DelegateInfoEntity::getToUserName)
                    .collect(Collectors.toList());
            vo.setToUserName(String.join(",", toUserNameList));
            long rejectCount = infoList.stream().filter(e -> ObjectUtil.equals(e.getStatus(), 2)).count();
            long acceptCount = infoList.stream().filter(e -> ObjectUtil.equals(e.getStatus(), 1)).count();
            if (time >= vo.getEndTime() || rejectCount == infoList.size()) {// 已失效，1、所有人都拒绝；2、到达结束时间或终止委托
                vo.setStatus(2);
            } else if (time >= vo.getStartTime() && acceptCount > 0) {// 生效中，对方接受且到达开始时间的状态
                vo.setStatus(1);
            } else {// 未生效，两种场景1：对方已接受但未达到开始时间状态为未生效，2、对方未接受状态为未生效
                vo.setStatus(0);
            }
            if (acceptCount > 0) {
                vo.setIsEdit(false);
            }
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public DelegateEntity getInfo(String id) {
        if (StringUtil.isBlank(id)) {
            return null;
        }
        return this.getById(id);
    }

    @Override
    public void create(DelegateCrForm fo) {
        String userId = UserProvider.getLoginUserId();
        DelegateEntity entity = JsonUtil.getJsonToBean(fo, DelegateEntity.class);
        entity.setId(RandomUtil.uuId());
        entity.setSortCode(RandomUtil.parses());
        entity.setCreatorUserId(userId);

        this.save(entity);
        delegateInfoService.create(fo, entity);
    }

    @Override
    public boolean update(DelegateEntity entity, DelegateUpForm fo) {
        BeanUtil.copyProperties(fo, entity, CopyOptions.create().setIgnoreNullValue(true));
        UserInfo userInfo = UserProvider.getUser();
        entity.setLastModifyTime(new Date());
        entity.setLastModifyUserId(userInfo.getUserId());
        delegateInfoService.update(fo, entity);
        return this.updateById(entity);
    }

    @Override
    public boolean updateStop(String id, DelegateEntity entity) {
        UserInfo userInfo = UserProvider.getUser();
        entity.setId(id);
        entity.setLastModifyTime(new Date());
        entity.setLastModifyUserId(userInfo.getUserId());
        DelegateModel delegate = new DelegateModel();
        List<DelegateInfoEntity> infoList = delegateInfoService.getList(entity.getId());
        delegate.setToUserIds(infoList.stream().map(DelegateInfoEntity::getToUserId).collect(Collectors.toList()));
        delegate.setType(FlowNature.EndMsg);
        delegate.setUserInfo(userInfo);
        boolean isDelegate = ObjectUtil.equals(entity.getType(), 0);
        delegate.setDelegate(isDelegate);
        msgUtil.delegateMsg(delegate);
        return this.updateById(entity);
    }

    @Override
    public void delete(DelegateEntity entity) {
        this.removeById(entity.getId());
    }

    @Override
    public List<String> getToUser(String userId, String flowId) {
        Date thisTime = DateUtil.getNowDate();
        QueryWrapper<DelegateEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DelegateEntity::getType, 1);
        queryWrapper.lambda().le(DelegateEntity::getStartTime, thisTime).ge(DelegateEntity::getEndTime, thisTime);
        if (StringUtil.isNotEmpty(userId)) {
            queryWrapper.lambda().eq(DelegateEntity::getUserId, userId);
        }
        List<DelegateEntity> list = this.list(queryWrapper);
        List<DelegateEntity> listRes = new ArrayList<>();
        if (StringUtil.isNotEmpty(flowId)) {
            for (DelegateEntity item : list) {
                if (StringUtil.isNotEmpty(item.getFlowId())) {
                    String[] split = item.getFlowId().split(",");
                    if (Arrays.asList(split).contains(flowId)) {
                        listRes.add(item);
                    }
                } else {// 为空是全部流程
                    listRes.add(item);
                }
            }
        } else {
            listRes = list;
        }
        List<String> toUser = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(listRes)) {
            List<String> ids = listRes.stream().map(DelegateEntity::getId).distinct().collect(Collectors.toList());
            List<DelegateInfoEntity> infoList = delegateInfoService.getList(ids);
            toUser = infoList.stream().filter(e -> ObjectUtil.equals(e.getStatus(), 1))
                    .map(DelegateInfoEntity::getToUserId).collect(Collectors.toList());
        }
        return toUser;
    }

    @Override
    public List<DelegateEntity> getByToUserId(String toUserId) {
        return this.getByToUserId(toUserId, 1);
    }

    // 根据 被委托人/代理人id 获取列表
    @Override
    public List<DelegateEntity> getByToUserId(String toUserId, Integer type) {
        List<DelegateInfoEntity> infoList = delegateInfoService.getByToUserId(toUserId);
        List<String> ids = infoList.stream().filter(e -> ObjectUtil.equals(e.getStatus(), 1))
                .map(DelegateInfoEntity::getDelegateId).distinct().collect(Collectors.toList());
        List<DelegateEntity> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(ids)) {
            Date thisTime = DateUtil.getNowDate();
            QueryWrapper<DelegateEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().in(DelegateEntity::getId, ids).eq(DelegateEntity::getType, type)
                    .le(DelegateEntity::getStartTime, thisTime).ge(DelegateEntity::getEndTime, thisTime);
            list = this.list(queryWrapper);
        }
        return list;
    }

    // 获取我的委托发起（统一到发起流程列表，待删除）
    @Override
    public List<TemplatePageLisVO> getFlow(TemplatePagination pagination) {
        List<DelegateEntity> list = this.getLaunchDelagateList();
        if (list.isEmpty()) {
            return new ArrayList<>();
        }

        List<String> templateIdList = new ArrayList<>();
        int num = 0;
        for (DelegateEntity entity : list) {
            if (StringUtil.isNotEmpty(entity.getFlowId())) {
                templateIdList.addAll(Arrays.asList(entity.getFlowId().split(",")));
            }
            num += StringUtil.isEmpty(entity.getFlowId()) ? 1 : 0;
        }
        if (num == 0) {
            pagination.setTemplateIdList(templateIdList);
        }

        List<TemplateEntity> templateList = templateService.getListAll(pagination, true);
        return JsonUtil.getJsonToList(templateList, TemplatePageLisVO.class);
    }

    @Override
    public ListVO<CandidateUserVo> getUserList(String templateId) throws WorkFlowException {
        String userId = UserProvider.getLoginUserId();
        TemplateEntity template = templateService.getById(templateId);
        if (null == template) {
            TemplateJsonEntity jsonEntity = templateJsonService.getById(templateId);
            if (null != jsonEntity) {
                template = templateService.getById(jsonEntity.getTemplateId());
            }
        }
        if (null == template) {
            throw new WorkFlowException(MsgCode.WF122.get());
        }
        if (!ObjectUtil.equals(template.getStatus(), 1)) {
            throw new WorkFlowException(MsgCode.WF140.get());
        }
        List<String> userIds = this.getDelegateUser(userId, template);
        List<UserEntity> userName = serviceUtil.getUserName(userIds);

        List<String> userIdAll = userName.stream().map(UserEntity::getId).collect(Collectors.toList());
        Map<String, List<UserRelationEntity>> userMap = serviceUtil.getListByUserIdAll(userIdAll).stream()
                .filter(t -> PermissionConst.ORGANIZE.equals(t.getObjectType()))
                .collect(Collectors.groupingBy(UserRelationEntity::getUserId));
        List<CandidateUserVo> jsonToList = new ArrayList<>();
        for (UserEntity entity : userName) {
            List<UserRelationEntity> listByUserId = userMap.get(entity.getId()) != null ? userMap.get(entity.getId())
                    : new ArrayList<>();
            StringJoiner joiner = new StringJoiner(",");
            for (UserRelationEntity relation : listByUserId) {
                List<OrganizeEntity> organizeId = serviceUtil.getOrganizeId(relation.getObjectId());
                if (organizeId.size() > 0) {
                    String organizeName = organizeId.stream().map(OrganizeEntity::getFullName)
                            .collect(Collectors.joining("/"));
                    joiner.add(organizeName);
                }
            }
            CandidateUserVo vo = JsonUtil.getJsonToBean(entity, CandidateUserVo.class);
            vo.setFullName(entity.getRealName() + "/" + entity.getAccount());
            vo.setHeadIcon(UploaderUtil.uploaderImg(entity.getHeadIcon()));
            vo.setOrganize(joiner.toString());
            jsonToList.add(vo);
        }
        if (jsonToList.isEmpty()) {
            throw new WorkFlowException(MsgCode.WF125.get());
        }
        ListVO<CandidateUserVo> vo = new ListVO<>();
        vo.setList(jsonToList);
        return vo;
    }

    public List<String> getDelegateUser(String userId, TemplateEntity template) throws WorkFlowException {
        List<String> ids = new ArrayList<>();
        List<DelegateEntity> delegateList = this.getByToUserId(userId, 0);
        if (CollectionUtil.isNotEmpty(delegateList)) {
            int permissionCount = 0;
            for (DelegateEntity delegateEntity : delegateList) {
                String flowId = delegateEntity.getFlowId();
                if (StringUtil.isNotBlank(flowId)) {
                    if (flowId.contains(template.getId())) {
                        if (ObjectUtil.equals(template.getVisibleType(), 1)) {
                            ids.add(delegateEntity.getUserId());
                            continue;
                        }
                        List<String> launchPermission = serviceUtil.getLaunchPermission(delegateEntity.getUserId());
                        if (launchPermission.contains(template.getId())) {
                            ids.add(delegateEntity.getUserId());
                        } else {
                            permissionCount++;
                        }
                    }
                } else {
                    // 全部流程
                    if (ObjectUtil.equals(template.getVisibleType(), 1)) {
                        ids.add(delegateEntity.getUserId());
                        continue;
                    }
                    List<String> launchPermission = serviceUtil.getLaunchPermission(delegateEntity.getUserId());
                    if (launchPermission.contains(template.getId())) {
                        ids.add(delegateEntity.getUserId());
                    } else {
                        permissionCount++;
                    }
                }
            }
            if (CollectionUtil.isEmpty(ids) && delegateList.size() == permissionCount) {
                throw new WorkFlowException(MsgCode.WF129.get());
            }
        }
        return ids;
    }

    /**
     * 获取当前用户所有发起委托列表
     */
    @Override
    public List<DelegateEntity> getLaunchDelagateList() {
        String userId = UserProvider.getLoginUserId();
        Date thisTime = DateUtil.getNowDate();
        List<DelegateInfoEntity> infoList = delegateInfoService.getByToUserId(userId);
        List<String> ids = infoList.stream().filter(e -> ObjectUtil.equals(e.getStatus(), 1))
                .map(DelegateInfoEntity::getDelegateId).distinct().collect(Collectors.toList());
        if (CollectionUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        QueryWrapper<DelegateEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(DelegateEntity::getId, ids)
                .le(DelegateEntity::getStartTime, thisTime).ge(DelegateEntity::getEndTime, thisTime)
                .eq(DelegateEntity::getType, 0);
        return this.list(queryWrapper);
    }

    @Override
    public List<DelegateEntity> selectSameParamAboutDelaget(DelegateCrForm fo) {
        List<DelegateInfoEntity> infoList = delegateInfoService.getByToUserIds(fo.getToUserId());
        if (CollectionUtil.isEmpty(infoList)) {
            return new ArrayList<>();
        }
        List<String> ids = infoList.stream().map(DelegateInfoEntity::getDelegateId).distinct()
                .collect(Collectors.toList());
        QueryWrapper<DelegateEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DelegateEntity::getUserId, fo.getUserId()).in(DelegateEntity::getId, ids)
                .eq(DelegateEntity::getType, Integer.valueOf(fo.getType()))
                .gt(DelegateEntity::getEndTime, new Date());
        return this.list(queryWrapper);
    }

    @Override
    public List<DelegateEntity> getList() {
        String userId = UserProvider.getLoginUserId();
        QueryWrapper<DelegateEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .and(t -> t.eq(DelegateEntity::getCreatorUserId, userId).or().eq(DelegateEntity::getUserId, userId));
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public void notarize(DelegateInfoEntity delegateInfo) {
        delegateInfoService.updateById(delegateInfo);
        // 判断全部拒绝，更新时间
        DelegateEntity entity = this.getById(delegateInfo.getDelegateId());
        List<DelegateInfoEntity> infoList = delegateInfoService.getList(entity.getId());
        boolean isAllReject = infoList.stream().allMatch(e -> ObjectUtil.equals(e.getStatus(), 2));
        if (isAllReject) {
            Date date = new Date();
            entity.setStartTime(date);
            entity.setEndTime(date);
            this.updateById(entity);
        }
        if (!ObjectUtil.equals(delegateInfo.getStatus(), 0)) {
            UserInfo userInfo = UserProvider.getUser();
            List<String> toUserIds = ImmutableList.of(entity.getUserId());

            SentMessageForm flowMsgModel = new SentMessageForm();
            flowMsgModel.setToUserIds(toUserIds);
            flowMsgModel.setUserInfo(userInfo);
            flowMsgModel.setTemplateId("PZXTLG022");
            Map<String, Object> parameterMap = new HashMap<>();
            parameterMap.put(FlowConstant.MANDATOR, userInfo.getUserName());
            parameterMap.put(FlowConstant.TITLE, ObjectUtil.equals(entity.getType(), 0) ? "委托" : "代理");
            parameterMap.put(FlowConstant.ACTION, ObjectUtil.equals(delegateInfo.getStatus(), 1) ? "接受" : "拒绝");
            flowMsgModel.setParameterMap(parameterMap);

            Integer delegateType = FlowNature.EndMsg.equals(entity.getType()) ? 0
                    : ObjectUtil.equals(entity.getType(), 0) ? 1 : 3;
            Map<String, String> contentMsg = new HashMap<>();
            contentMsg.put("type", delegateType + "");
            flowMsgModel.setContentMsg(contentMsg);
            flowMsgModel.setFlowType(2);
            flowMsgModel.setType(2);

            List<SentMessageForm> messageListAll = new ArrayList<>();
            messageListAll.add(flowMsgModel);
            serviceUtil.sendDelegateMsg(messageListAll);
        }
    }
}
