package com.artfess.xqxt.meeting.manager.impl;


import cn.hutool.json.JSONObject;
import com.artfess.base.context.BaseContext;
import com.artfess.base.feign.UCFeignService;
import com.artfess.base.manager.BaseManager;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.model.CommonResult;
import com.artfess.base.query.*;
import com.artfess.base.util.CommonUtil;
import com.artfess.base.util.HttpUtil;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.bpm.persistence.model.DefaultBpmTask;
import com.artfess.integrate.consts.WeChatWorkConsts;
import com.artfess.integrate.model.SysExternalUnite;
import com.artfess.integrate.persistence.dao.SysExternalUniteDao;
import com.artfess.integrate.persistence.manager.impl.WxUserService;
import com.artfess.poi.util.ExcelUtil;
import com.artfess.redis.util.RedisUtil;
import com.artfess.security.model.BackupLog;
import com.artfess.sysConfig.persistence.manager.SysDictionaryManager;
import com.artfess.sysConfig.persistence.manager.SysIdentityManager;
import com.artfess.sysConfig.persistence.param.DictModel;
import com.artfess.uc.api.model.IUser;
import com.artfess.uc.dao.OrgDao;
import com.artfess.uc.dao.UserDao;
import com.artfess.uc.exception.BaseException;
import com.artfess.uc.manager.UserGroupManager;
import com.artfess.uc.model.Org;
import com.artfess.uc.model.User;
import com.artfess.uc.model.UserGroup;
import com.artfess.uc.params.user.UserVo;
import com.artfess.uc.util.ContextUtil;
import com.artfess.xqxt.meeting.dao.MeetingDao;
import com.artfess.xqxt.meeting.dao.MeetingPlaceDao;
import com.artfess.xqxt.meeting.dao.MeetingUserDao;
import com.artfess.xqxt.meeting.dto.MeetingDTO;
import com.artfess.xqxt.meeting.m900.bean.*;
import com.artfess.xqxt.meeting.m900.response.CreateConferenceResponse;
import com.artfess.xqxt.meeting.m900.response.EndConferenceResponse;
import com.artfess.xqxt.meeting.m900.response.ProlongConferenceResponse;
import com.artfess.xqxt.meeting.manager.*;
import com.artfess.xqxt.meeting.model.*;
import com.artfess.xqxt.meeting.utils.BizUtil;
import com.artfess.xqxt.meeting.utils.BizUtils;
import com.artfess.xqxt.meeting.utils.Sha1;
import com.artfess.xqxt.meeting.utils.SortList;
import com.artfess.xqxt.meeting.vo.*;
import com.aspose.slides.internal.m0.and;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
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.ctc.wstx.dtd.TokenModel;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.gson.JsonObject;
import com.jogamp.common.util.ArrayHashMap;
import jogamp.nativewindow.jawt.JAWTUtil;
import lombok.extern.slf4j.Slf4j;
import net.hasor.db.transaction.interceptor.Transactional;
import net.hasor.utils.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.joda.time.LocalDate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.RollbackException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MeetingManagerImpl extends BaseManagerImpl<MeetingDao, Meeting> implements MeetingManager {


    @Resource
    SysDictionaryManager sysDictionaryManager;
    @Resource
    MeetingUserDao meetingUserDao;
    @Resource
    MeetingDao meetingDao;
    @Resource
    MeetingPlaceDao meetingPlaceDao;
    @Resource
    BaseContext baseContext;
    @Resource
    SysExternalUniteDao sysExternalUniteDao;
    @Resource
    UCFeignService uCFeignService;
    @Resource
    ZTEManager zteManager;
    @Resource
    BizTerminalManager bizTerminalManager;
    @Resource
    BizSiteParamExManager bizSiteParamExManager;
    @Resource
    private MeetingUserManager meetingUserManager;

    @Resource
    private BizMeetingAccessoryManager meetingAccessoryManager;

    @Resource
    private BizMeetingVoteManager bizMeetingVoteManager;

    @Resource
    private OrgDao orgDao;
    @Resource
    private UserGroupManager userGroupManager;

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserDao userDao;
    @Autowired
    UserGroupManager userGroupService;

    @Resource
    private SysIdentityManager sysIdentityManager;


    @Override
    public void exportMeeting(String id, HttpServletResponse response) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        Meeting meeting = this.getById(id);
        //创建表格
        XSSFWorkbook workbook = new XSSFWorkbook();
        if (meeting!=null){
            String fileName = meeting.getTheme()+".xlsx";
            //获取数据
            QueryWrapper<MeetingUser> totalQueryWrapper = new QueryWrapper<>();
            totalQueryWrapper.eq("MEETING_ID_",meeting.getId());
            List<MeetingUser> users = meetingUserManager.list(totalQueryWrapper);
            if(null != users && users.size() > 0){
                for (MeetingUser meetingUser : users){
                    String currentDeptId = ContextUtil.getCurrentDeptId(meetingUser.getUserId());
                    if(StringUtil.isNotEmpty(currentDeptId)){
                        meetingUser.setDeptId(currentDeptId);
                        meetingUser.setDeptName(ContextUtil.getCurrentDeptName(meetingUser.getUserId()));
                    }else {
                        meetingUser.setDeptId(ContextUtil.getCurrentOrgId(meetingUser.getUserId()));
                        meetingUser.setDeptName(ContextUtil.getCurrentOrgName(meetingUser.getUserId()));
                    }
                }
                //按depId升序
                SortList<MeetingUser> sortList = new SortList<MeetingUser>();
                sortList.Sort(users, "getDeptId", "asc");
            }

            int total = meetingUserManager.count(totalQueryWrapper);
            QueryWrapper<MeetingUser> signInCountQueryWrapper = new QueryWrapper<>();
            signInCountQueryWrapper.eq("MEETING_ID_",meeting.getId());
            signInCountQueryWrapper.eq("SIGN_IN_STATUS_", 0);
            int signInCount = meetingUserManager.count(signInCountQueryWrapper);
            int unSignInCount = total - signInCount;
            //组装表格
            XSSFSheet sheet = workbook.createSheet();
            XSSFRow row = sheet.createRow(0);
            XSSFCell cell = row.createCell(0);
            cell.setCellValue("视频会议基本数据");

            XSSFRow row1 = sheet.createRow(1);
            XSSFCell cell1 = row1.createCell(0);
            cell1.setCellValue("会议主题");
            XSSFCell cell2 = row1.createCell(1);
            cell2.setCellValue("会议开始时间");
            XSSFCell cell3 = row1.createCell(2);
            cell3.setCellValue("累计会议时长");
            XSSFCell cell4 = row1.createCell(3);
            cell4.setCellValue("会议创建者");
            XSSFCell cell5 = row1.createCell(4);
            cell5.setCellValue("会议邀请成员总数");
            XSSFCell cell6 = row1.createCell(5);
            cell6.setCellValue("已入会");
            XSSFCell cell7 = row1.createCell(6);
            cell7.setCellValue("未入会");
            XSSFCell cell8 = row1.createCell(7);
            cell8.setCellValue("参会比例");

            XSSFRow row2 = sheet.createRow(2);
            XSSFCell row2cell1 = row2.createCell(0);
            row2cell1.setCellValue(meeting.getTheme());
            XSSFCell row2cell2 = row2.createCell(1);
            row2cell2.setCellValue(df.format(meeting.getStartTime()));
            XSSFCell row2cell3 = row2.createCell(2);
            if (meeting.getEndTime() !=null){
                row2cell3.setCellValue(this.getDate(meeting.getStartTime(),meeting.getEndTime()));
            }else {
                row2cell3.setCellValue(this.getDate(meeting.getStartTime(),LocalDateTime.now()));
            }
            XSSFCell row2cell4 = row2.createCell(3);
            row2cell4.setCellValue(meeting.getCreateName());
            XSSFCell row2cell5 = row2.createCell(4);
            row2cell5.setCellValue(total);
            XSSFCell row2cell6 = row2.createCell(5);
            row2cell6.setCellValue(signInCount);
            XSSFCell row2cell7 = row2.createCell(6);
            row2cell7.setCellValue(unSignInCount);
            XSSFCell row2cell8 = row2.createCell(7);
            NumberFormat numberFormat = NumberFormat.getInstance();
            numberFormat.setMaximumFractionDigits(2);
            if(total == 0){
                row2cell8.setCellValue("0.0%");
            }else {
                row2cell8.setCellValue(numberFormat.format((double)signInCount  / (double)total *100 )+"%");
            }


            XSSFRow row4 = sheet.createRow(4);
            XSSFCell row4Cell = row4.createCell(0);
            row4Cell.setCellValue("参会数据");

            XSSFRow row5 = sheet.createRow(5);
            XSSFCell row5Cell1 = row5.createCell(0);
            row5Cell1.setCellValue("姓名");

            XSSFCell row5Cell11 = row5.createCell(1);
            row5Cell11.setCellValue("科室");

            //反馈状态，0：已反馈，1：未反馈，默认为1
            XSSFCell row5Cell2 = row5.createCell(2);
            row5Cell2.setCellValue("反馈状态");
            // 反馈结果，1：准时参加会议，2：推迟参加会议，3：不能参加会议
            XSSFCell row5Cell3 = row5.createCell(3);
            row5Cell3.setCellValue("反馈结果");
            // 反馈时间
            XSSFCell row5Cell4 = row5.createCell(4);
            row5Cell4.setCellValue("反馈时间");
            // 会议签到状态
            XSSFCell row5Cell5 = row5.createCell(5);
            row5Cell5.setCellValue("会议签到状态");

            XSSFCell row5Cell6 = row5.createCell(6);
            row5Cell6.setCellValue("签到时间");

            XSSFCell row5Cell7 = row5.createCell(7);
            row5Cell7.setCellValue("签退状态");

            XSSFCell row5Cell8 = row5.createCell(8);
            row5Cell8.setCellValue("签退时间");
            XSSFCell row5Cell9 = row5.createCell(9);
            row5Cell9.setCellValue("累计参会时长");
            XSSFCell row5Cell10 = row5.createCell(10);
            row5Cell10.setCellValue("未入会原因");

            int num = 6;
            for (MeetingUser meetingUser :users){
                XSSFRow userRow = sheet.createRow(num);
                num++;
                XSSFCell userCell1 = userRow.createCell(0);
                userCell1.setCellValue(meetingUser.getUserName());

                XSSFCell depCell = userRow.createCell(1);
                depCell.setCellValue(meetingUser.getDeptName());

                XSSFCell userCell2 = userRow.createCell(2);
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(meetingUser.getFeedBackStatus())&& "1".equals(meetingUser.getFeedBackStatus())){
                    userCell2.setCellValue("未反馈");
                }else {
                    userCell2.setCellValue("已反馈");
                }

                XSSFCell userCell3 = userRow.createCell(3);
                String feedBack;
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(meetingUser.getFeedBack())){
                    switch (meetingUser.getFeedBack()){
                        case "1":feedBack="准时参加会议";break;
                        case "2":feedBack="推迟参加会议";break;
                        case "3":feedBack="不能参加会议";break;
                        case "4":feedBack="委托他人参会";break;
                        default:feedBack="";break;
                    }
                    userCell3.setCellValue(feedBack);
                }else {
                    userCell3.setCellValue("");
                }


                XSSFCell userCell4 = userRow.createCell(4);
                if (meetingUser.getFeedBackDate()!=null){
                    userCell4.setCellValue(df.format(meetingUser.getFeedBackDate()));
                }

                XSSFCell userCell5 = userRow.createCell(5);
                if (meetingUser.getSignInStatus()==1){
                    userCell5.setCellValue("未签到");
                }else {
                    userCell5.setCellValue("已签到");
                }

                XSSFCell userCell6 = userRow.createCell(6);
                if (meetingUser.getFirstMembershipDate()!=null){
                    userCell6.setCellValue(df.format(meetingUser.getFirstMembershipDate()));
                }

                XSSFCell userCell7 = userRow.createCell(7);
                if (meetingUser.getSignOutStatus() == 1){
                    userCell7.setCellValue("未签退");
                }else {
                    userCell7.setCellValue("已签退");
                }

                XSSFCell userCell8 = userRow.createCell(8);
                if (meetingUser.getLastExitDate()!=null){
                    userCell8.setCellValue(df.format(meetingUser.getLastExitDate()));
                }

                XSSFCell userCell9 = userRow.createCell(9);
                if (meetingUser.getFirstMembershipDate()==null && meetingUser.getLastExitDate() == null){
                    userCell9.setCellValue("00:00:00");
                }
                if (meetingUser.getFirstMembershipDate()!=null){
                    LocalDateTime endTime = meetingUser.getLastExitDate()==null?LocalDateTime.now():meetingUser.getLastExitDate();
                    userCell9.setCellValue(this.getDate(meetingUser.getFirstMembershipDate(),endTime));
                }


                XSSFCell userCell10 = userRow.createCell(10);
                userCell10.setCellValue(meetingUser.getNotJoiningReasons());
            }

        }
        try {
            ExcelUtil.downloadExcel(workbook,meeting.getTheme()+".xlsx",response);
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("导出列表失败！");
        }



    }


    public static String getDate(LocalDateTime startTime, LocalDateTime endTime) {
        long nowSecond = startTime.toEpochSecond(ZoneOffset.ofHours(0));
        long endSecond = endTime.toEpochSecond(ZoneOffset.ofHours(0));
        long absSeconds = Math.abs(nowSecond - endSecond);
        long s = absSeconds % 60;
        String second = String.valueOf(s);
        long m = absSeconds / 60 % 60;
        String minute = String.valueOf(m);
        long h = absSeconds / 60 / 60;
        String hour = String.valueOf(h);
        second = second.length() == 1 ? "0" + second : second;
        minute = minute.length() == 1 ? "0" + minute : minute;
        hour = hour.length() == 1 ? "0" + hour : hour;
        return hour + ":" + minute + ":" + second;

    }


    @Override
    public List<MeetingUser> signInUserList(String meetingId, Integer type) {
        QueryWrapper<MeetingUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MEETING_ID_",meetingId);
        if (type != 3){
            queryWrapper.eq("SIGN_IN_STATUS_",type);
        }
        List<MeetingUser> list = meetingUserManager.list(queryWrapper);
        if(null != list && list.size() > 0){
            for (MeetingUser meetingUser : list){
                if(StringUtil.isNotEmpty(meetingUser.getUserId())){
                    if(StringUtil.isNotEmpty(ContextUtil.getCurrentDeptId(meetingUser.getUserId()))){
                        meetingUser.setDeptId(ContextUtil.getCurrentDeptId(meetingUser.getUserId()));
                        meetingUser.setDeptName(ContextUtil.getCurrentDeptName(meetingUser.getUserId()));
                    }else {
                        meetingUser.setDeptId(ContextUtil.getCurrentOrgId(meetingUser.getUserId()));
                        meetingUser.setDeptName(ContextUtil.getCurrentOrgName(meetingUser.getUserId()));
                    }
                }
            }
            //按depId升序
            SortList<MeetingUser> sortList = new SortList<MeetingUser>();
            sortList.Sort(list, "getDeptId", "asc");
        }
        return list;
    }

    @Override
    public List<MeetingUser> signOutUserList(String meetingId, Integer type) {
        QueryWrapper<MeetingUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MEETING_ID_",meetingId);
        if (type != 3){
            queryWrapper.eq("SIGN_OUT_STATUS_",type);
        }
        List<MeetingUser> list = meetingUserManager.list(queryWrapper);
        if(null != list && list.size() > 0){
            for (MeetingUser meetingUser : list){
                if(StringUtil.isNotEmpty(meetingUser.getUserId())){
                    if(StringUtil.isNotEmpty(ContextUtil.getCurrentDeptId(meetingUser.getUserId()))){
                        meetingUser.setDeptId(ContextUtil.getCurrentDeptId(meetingUser.getUserId()));
                        meetingUser.setDeptName(ContextUtil.getCurrentDeptName(meetingUser.getUserId()));
                    }else {
                        meetingUser.setDeptId(ContextUtil.getCurrentOrgId(meetingUser.getUserId()));
                        meetingUser.setDeptName(ContextUtil.getCurrentOrgName(meetingUser.getUserId()));
                    }
                }
            }
            //按depId升序
            SortList<MeetingUser> sortList = new SortList<MeetingUser>();
            sortList.Sort(list, "getDeptId", "asc");
        }
        return list;
    }

    @Override
    public SignInAndOutCountVo signInAndOutCount(String meetingId) {
        SignInAndOutCountVo signInAndOutCountVo = new SignInAndOutCountVo();
        // 总人数
        QueryWrapper<MeetingUser> totalQueryWrapper = new QueryWrapper<>();
        totalQueryWrapper.eq("MEETING_ID_",meetingId);
        int total = meetingUserManager.count(totalQueryWrapper);
        // 已签到人数
        QueryWrapper<MeetingUser> signInCountQueryWrapper = new QueryWrapper<>();
        signInCountQueryWrapper.eq("MEETING_ID_",meetingId);
        signInCountQueryWrapper.eq("SIGN_IN_STATUS_", 0);
        int signInCount = meetingUserManager.count(signInCountQueryWrapper);
        // 未签到人数
        int unSignInCount = total - signInCount;
        // 已签退人数
        QueryWrapper<MeetingUser> signOuntCountQueryWrapper = new QueryWrapper<>();
        signOuntCountQueryWrapper.eq("MEETING_ID_",meetingId);
        signOuntCountQueryWrapper.eq("SIGN_OUT_STATUS_", 0);
        int signOuntCount = meetingUserManager.count(signOuntCountQueryWrapper);
        // 未签退人数
        int unSignOunt = total - signOuntCount;
        signInAndOutCountVo.setTotal(total);
        signInAndOutCountVo.setSignInCount(signInCount);
        signInAndOutCountVo.setUnSignInCount(unSignInCount);
        signInAndOutCountVo.setSignOunt(signOuntCount);
        signInAndOutCountVo.setUnSignOunt(unSignOunt);
        return signInAndOutCountVo;
    }

    @Override
    public MeetingUser getMeetingUserByMeetingIdAndUserId(String meetingId, String userId) {
        QueryWrapper<MeetingUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MEETING_ID_",meetingId);
        queryWrapper.eq("USER_ID_",userId);
        List<MeetingUser> list = meetingUserManager.list(queryWrapper);
        if(null == list || list.size() == 0){
            return null;
        }
        for (MeetingUser meetingUser : list){
            if(StringUtil.isNotEmpty(meetingUser.getUserId())){
                if(StringUtil.isNotEmpty(ContextUtil.getCurrentDeptId(meetingUser.getUserId()))){
                    meetingUser.setDeptId(ContextUtil.getCurrentDeptId(meetingUser.getUserId()));
                    meetingUser.setDeptName(ContextUtil.getCurrentDeptName(meetingUser.getUserId()));
                }else {
                    meetingUser.setDeptId(ContextUtil.getCurrentOrgId(meetingUser.getUserId()));
                    meetingUser.setDeptName(ContextUtil.getCurrentOrgName(meetingUser.getUserId()));
                }
            }
        }
        //按depId升序
        SortList<MeetingUser> sortList = new SortList<MeetingUser>();
        sortList.Sort(list, "getDeptId", "asc");
        return list.get(0);
    }

    @Override
    public List<BizSiteParamExVO> getSiteListByMeetingId(String meetingId) {
        // 直接调用中兴接口查询列表
        List<MeetingPlace> placeNameList = meetingDao.findPlaceName(meetingId);
        if(null != placeNameList){
            List<BizSiteParamExVO> siteParamExList = new ArrayList<>(placeNameList.size());
            int i = 0;
            for (MeetingPlace meetingPlace : placeNameList){
                BizSiteParamExVO vo  = new BizSiteParamExVO();
                BeanUtils.copyProperties(meetingPlace, vo);
                vo.setName(meetingPlace.getPlaceName());
                vo.setAlias(meetingPlace.getPlaceName());
                vo.setTerminalId(meetingPlace.getTerminalId());
                BizTerminal terminal = new BizTerminal();
                BeanUtils.copyProperties(meetingPlace, terminal);
                terminal.setId(meetingPlace.getTerminalId());
                terminal.setTerminalName(meetingPlace.getPlaceName());
                terminal.setTerminalId(meetingPlace.getTerminalId());
                terminal.setIpAddress(meetingPlace.getIpAddress());
                vo.setTerType("普通终端");
                if(i%2 == 0){
                    terminal.setStatus("connected");
                    vo.setStatus("connected");
                    vo.setMute(true);
                    vo.setMaxVolume(true);
                    vo.setSilent(true);
                }else {
                    terminal.setStatus("disconnected");
                    vo.setStatus("disconnected");
                    vo.setMute(false);
                    vo.setMaxVolume(false);
                    vo.setSilent(false);
                }
                vo.setBizTerminal(terminal);
                siteParamExList.add(vo);
                i++;
            }
            return siteParamExList;
        }
        return null;
    }

    @Override
    @Transactional
    public Integer updateMeetingUser(MeetingUser meetingUser) {
        return meetingUserDao.updateById(meetingUser);
    }


    @Override
    public Integer signIn(String meetingId, String userId) {
        Meeting meeting = meetingDao.selectById(meetingId);
        if(null != meeting){
            LocalDateTime startTime = meeting.getStartTime();
            LocalDateTime endTime = meeting.getEndTime();
            if(null != startTime){
                LocalDateTime now = LocalDateTime.now();
                Duration duration = Duration.between(now, startTime);
                //相差的分钟数
                long minutes = duration.toMinutes();
                if(minutes > 30L){
                    throw new BaseException("签到失败，会议开始前30分钟才允许签到！");
                }
                if(null != endTime && now.isAfter(endTime)){
                    throw new BaseException("签到失败，会议已结束！");
                }
                if(minutes < - 6L){
                    throw new BaseException("签到失败，会议开始后禁止签到！");
                }
            }
        }
        UpdateWrapper<MeetingUser> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("MEETING_ID_", meetingId).eq("USER_ID_", userId);
        updateWrapper.set("SIGN_IN_STATUS_", 0).set("FIRST_MEMBERSHIP_DATE_", LocalDateTime.now());
        meetingUserManager.update(updateWrapper);
        return 1;
    }

    @Override
    public Integer disSignIn(String meetingId, String userId) {
        return meetingUserDao.updateInStatus(1,meetingId,userId);
    }

    @Override
    public Integer signOut(String meetingId, String userId) {
        UpdateWrapper<MeetingUser> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("MEETING_ID_", meetingId).eq("USER_ID_", userId);
        updateWrapper.set("SIGN_OUT_STATUS_", 0).set("LAST_EXIT_DATE_", LocalDateTime.now()).set("SIGN_IN_TYPE_", 1);
        meetingUserManager.update(updateWrapper);
        return 1;
    }

    @Override
    public Integer disSignOut(String meetingId, String userId) {
        return meetingUserDao.updateOutStatus(1,1,meetingId,userId);
    }


    /**
     * 获取某个父节点下面的所有子节点
     *
     * @param orgList
     * @param parentId
     * @return
     */
    public static List<Org> getOrgChild(List<Org> orgList, String parentId, List<Org> rtnList) {
        for (Org org : orgList) {
            // 遍历出父id等于参数的id，add进子节点集合
            if (parentId.equals(org.getParentId())) {
                // 递归遍历下一级
                getOrgChild(orgList, org.getId(), rtnList);
                rtnList.add(org);
            }
        }
        return rtnList;
    }

    @Override
    public PageList<MeetingVO> getHistory(Integer type,QueryFilter<Meeting> queryFilter) {
        if (type == 1){
            String orgId ;
            if (org.apache.commons.lang3.StringUtils.isNotEmpty(baseContext.getCurrentOrgId())&&!"0".equals(baseContext.getCurrentOrgId())){
                orgId = baseContext.getCurrentOrgId();
            }else {
                orgId = "1419863231459102720";
            }
            QueryWrapper<Org> rgQueryWrapper = new QueryWrapper<>();
            rgQueryWrapper.eq("is_dele_","0");
            List<Org> allList = orgDao.selectList(rgQueryWrapper);
            List<Org> rtnList = new ArrayList<Org>();
            List<Org> orgList = getOrgChild(allList,orgId,rtnList);
            List<String> orgIds = orgList.stream().map(Org::getId).collect(Collectors.toList());
            if (orgIds != null && orgIds.size()>0){
                queryFilter.addFilter("CREATE_COMPANY_ID_",orgIds,QueryOP.IN);
            }
        }

        IPage<MeetingVO> list = meetingDao.selectByUserId
                (convert2IPage(queryFilter.getPageBean()), convert2Wrapper(queryFilter,currentModelClass()));
        for (MeetingVO meeting : list.getRecords()){
            List<MeetingUser> users = findUserName(meeting.getId());
            List<String> groups = users.stream().filter(e -> null != e.getUserGroup() && !"".equals(e.getUserGroup())).map(MeetingUser::getUserGroup).collect(Collectors.toList());

            if(null != groups && groups.size() > 0){
                QueryWrapper<UserGroup> queryWrapper = new QueryWrapper<>();
                queryWrapper.in("CODE_",groups);

                List<UserGroup> userGroups = userGroupManager.list(queryWrapper);

                meeting.setUserGroups(userGroups);
            }
            meeting.setUsers(users);



            meeting.setPlaces(findPlaceName(meeting.getId()));
        }
        list.setTotal(list.getRecords().size());
        return new PageList<MeetingVO>(list);
    }

    @Override
    public MeetingCountVO getMeetingCount() {

        MeetingCountVO vo = new MeetingCountVO();

        QueryFilter<Meeting> queryFilter = QueryFilter.build();
        PageBean pageBean = new PageBean();
        pageBean.setPage(1);
        pageBean.setPageSize(PageBean.WITHOUT_PAGE);
        queryFilter.setPageBean(pageBean);
        boolean flag = false;
        List<ObjectNode> nodes = uCFeignService.getRoleListByAccount(baseContext.getCurrentUserAccout());
        for (ObjectNode objectNode : nodes){
            if ("sysRole".equals(objectNode.get("code").asText())){
                flag = true;
                break;
            }
        }
        if (!flag){
            String userId = baseContext.getCurrentUserId();
//            List<String> userIds = meetingUserDao.selectByUserId(userId).stream().map(MeetingUser::getMeetingId).collect(Collectors.toList());
            List<String> userIds = meetingUserDao.queryMeetingIdByUserId(userId);
            if(null != userIds && userIds.size() > 0){
                // 查询参会人员是自己或者创建人是自己的会议
                queryFilter.addFilter("CREATE_BY_",baseContext.getCurrentUserId(),QueryOP.EQUAL,FieldRelation.AND, "userFilter");
                queryFilter.addFilter("ID_",userIds , QueryOP.IN, FieldRelation.OR, "userFilter");
            }else {
                // 如果没有要参加的会议，就直接查询创建人是自己的会议
                queryFilter.addFilter("CREATE_BY_",baseContext.getCurrentUserId(),QueryOP.EQUAL);
            }
        }
        queryFilter.addFilter("IS_DELE_",0, QueryOP.EQUAL);

        IPage<MeetingVO> list = meetingDao.selectByUserId
                (convert2IPage(queryFilter.getPageBean()), convert2Wrapper(queryFilter,currentModelClass()));
        List<MeetingVO> meetingVOS = list.getRecords();
        Integer status1 = meetingVOS.stream().filter(meetingVO -> Objects.equals(meetingVO.getMeetingStatus(),1)).collect(Collectors.toList()).size();
        Integer status2 = meetingVOS.stream().filter(meetingVO -> Objects.equals(meetingVO.getMeetingStatus(),2)).collect(Collectors.toList()).size();
        Integer status3 = meetingVOS.stream().filter(meetingVO -> Objects.equals(meetingVO.getMeetingStatus(),3)).collect(Collectors.toList()).size();
//        Integer status4 = meetingVOS.stream().filter(meetingVO -> Objects.equals(meetingVO.getMeetingStatus(),4)).collect(Collectors.toList()).size();
        vo.setFutureCount(String.valueOf(status1));
        vo.setRunCount(String.valueOf(status2));
        vo.setFinishCount(String.valueOf(status3));
        return vo;
    }

    @Override
    public PageList<MeetingVO> findByUserId(QueryFilter<Meeting> queryFilter) {
        boolean flag = false;
        List<ObjectNode> nodes = uCFeignService.getRoleListByAccount(baseContext.getCurrentUserAccout());
        for (ObjectNode objectNode : nodes){
            if ("sysRole".equals(objectNode.get("code").asText())){
                flag = true;
                break;
            }
        }
        if (!flag){
            String userId = baseContext.getCurrentUserId();
//            List<String> userIds = meetingUserDao.selectByUserId(userId).stream().map(MeetingUser::getMeetingId).collect(Collectors.toList());
            List<String> userIds = meetingUserDao.queryMeetingIdByUserId(userId);
            if(null != userIds && userIds.size() > 0){
                // 查询参会人员是自己或者创建人是自己的会议
                queryFilter.addFilter("CREATE_BY_",baseContext.getCurrentUserId(),QueryOP.EQUAL,FieldRelation.AND, "userFilter");
                queryFilter.addFilter("ID_",userIds , QueryOP.IN, FieldRelation.OR, "userFilter");
            }else {
                // 如果没有要参加的会议，就直接查询创建人是自己的会议
                queryFilter.addFilter("CREATE_BY_",baseContext.getCurrentUserId(),QueryOP.EQUAL);
            }
        }
        queryFilter.addFilter("IS_DELE_",0, QueryOP.EQUAL);
        List<FieldSort> sorter = queryFilter.getSorter();

        if(null == sorter || sorter.isEmpty() ){
            List<FieldSort> sorter1 = new ArrayList<FieldSort>();
            FieldSort sort1 = new FieldSort("START_TIME_", Direction.DESC);
            sorter1.add(sort1);
            queryFilter.setSorter(sorter1);
        }

        IPage<MeetingVO> list = meetingDao.selectByUserId
                (convert2IPage(queryFilter.getPageBean()), convert2Wrapper(queryFilter,currentModelClass()));
        for (MeetingVO meeting : list.getRecords()){
            List<MeetingUser> users = findUserName(meeting.getId());

            List<String> groups = users.stream().filter(e -> null != e.getUserGroup() && !"".equals(e.getUserGroup())).map(MeetingUser::getUserGroup).collect(Collectors.toList());

            if(null != groups && groups.size() > 0){
                QueryWrapper<UserGroup> queryWrapper = new QueryWrapper<>();
                queryWrapper.in("CODE_",groups);

                List<UserGroup> userGroups = userGroupManager.list(queryWrapper);

                meeting.setUserGroups(userGroups);
            }
            meeting.setUsers(users);
            meeting.setPlaces(findPlaceName(meeting.getId()));

            // 计算结束状态
//            LocalDateTime startTime = meeting.getStartTime();
            LocalDateTime endTime = meeting.getEndTime();
            //会议状态，1：未开始，2：进行中，3：已结束，4：取消
            Integer meetingStatus = meeting.getMeetingStatus();
            // 如果当前时间小于会议开始时间，则状态应该为未开始，

            // 如果当前时间大于等于会议开始时间，并且小于等于会议结束时间，则状态为进行中

            // 如果当前时间大于会议结束时间，则为已结束会议
            if(null != endTime && LocalDateTime.now().isAfter(endTime) && meetingStatus != 3 && meetingStatus != 4){
                meeting.setMeetingStatus(3);
            }
            //判断当前用户是否可以结束会议
            //结束会议只能是管理员和会议创建人才能结束
            IUser user= ContextUtil.getCurrentUser();
            //创建人ID
            String createBy = meeting.getCreateBy();
            boolean admin = user.isAdmin();

            if(admin || createBy.equals(user.getUserId())){
                meeting.setEndPower(1);
            }else {
                meeting.setEndPower(0);
            }
        }
        return new PageList<MeetingVO>(list);
    }

    @Override
    public MeetingVO findById(String meetingId) throws Exception{
        User currentUser = ContextUtil.getCurrentUser();
        String userId = currentUser.getId();
        Meeting meeting = meetingDao.selectById(meetingId);
        if (meeting == null) {
           throw new BaseException("会议不存在或者会议已经被删除！");
        };
        MeetingVO vo = new MeetingVO();
        Integer meetingType = meeting.getMeetingType();
        BeanUtils.copyProperties(meeting,vo);



        List<MeetingUser> users = findUserName(meeting.getId());

        List<String> groups = users.stream().filter(e -> null != e.getUserGroup() && !"".equals(e.getUserGroup())).map(MeetingUser::getUserGroup).collect(Collectors.toList());

        if(null != groups && groups.size() > 0){
            QueryWrapper<UserGroup> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("CODE_",groups);

            List<UserGroup> userGroups = userGroupManager.list(queryWrapper);

            vo.setUserGroups(userGroups);
        }
        vo.setUsers(users);


        vo.setPlaces(findPlaceName(meeting.getId()));
        vo.setId(meetingId);
        // 视频会议，查询最新会议状态
        if(meetingType == 2){
            //测试环境下注释中兴调用，注释掉就可以在测试环境进行测试
            zteManager.getConferenceStatus(vo);
        }
        // 设置当前登录人员的反馈状态及反馈信息
        QueryWrapper<MeetingUser> meetingUserQueryWrapper = new QueryWrapper<>();
        meetingUserQueryWrapper.eq("MEETING_ID_", meetingId).eq("USER_ID_", userId);
        List<MeetingUser> meetingUserList = meetingUserManager.list(meetingUserQueryWrapper);
        if(null != meetingUserList && meetingUserList.size() > 0){
            MeetingUser meetingUser = meetingUserList.get(0);
            vo.setFeedBack(meetingUser.getFeedBack());
            // 状态置为已反馈
            vo.setFeedBackStatus(meetingUser.getFeedBackStatus());
            // 预计入会时间
            vo.setEstimatedArrivalDate(meetingUser.getEstimatedArrivalDate());
            vo.setEstimatedArrivalTime(meetingUser.getEstimatedArrivalTime());
            vo.setNotJoiningReasons(meetingUser.getNotJoiningReasons());
            // 查询当前用户上传附件问题
            QueryWrapper<BizMeetingAccessory> accessoryQueryWrapper = new QueryWrapper<>();
            accessoryQueryWrapper.in("SOURCE_ID_", meetingUser.getId());
            meetingUser.setMeetingAccessoryList(meetingAccessoryManager.list(accessoryQueryWrapper));
        }
        return vo;
    }


    /**
     * 同步正在进行的会议
     * @return
     */
    @Override
    @Transactional
    public void synConferenceInfo() {
        // 1. 调用中兴查询正在进行会议信息
        List<ConferenceStatus> conferenceInfoList = zteManager.getConferenceInfoList();
        if(null != conferenceInfoList && conferenceInfoList.size() > 0){
            List meetingList = new ArrayList(conferenceInfoList.size());
            for (ConferenceStatus conferenceStatus : conferenceInfoList){
                // 2. 同步会议信息
                Meeting meeting = new Meeting();
                BeanUtils.copyProperties(conferenceStatus, meeting);
                Calendar calendar = conferenceStatus.getStartTime();
                LocalDateTime startTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
                meeting.setId(conferenceStatus.getConferenceIdentifier());
                meeting.setStartTime(startTime);
                int duration = conferenceStatus.getDuration();
                LocalDateTime endTime = startTime.plusMinutes(duration);
                meeting.setMeetingStatus(2);
                meeting.setEndTime(endTime);
                meeting.setTheme(conferenceStatus.getConferenceName());
                meeting.setContent(conferenceStatus.getConferenceName());
                meeting.setConferenceNumber(conferenceStatus.getConferenceNumber());
                meeting.setPassword(conferenceStatus.getConferencePassword());
                meeting.setIfRecord(conferenceStatus.isIfRecord());
                meeting.setRecordState(conferenceStatus.getRecordState());
                meeting.setLockState(conferenceStatus.isLockState());
                meeting.setConfCtrlMode(conferenceStatus.getConfCtrlMode());
                meeting.setBoardcaster(conferenceStatus.getBoardcaster());
                meeting.setDualBoardcaster(conferenceStatus.getDualBoardcaster());
                meeting.setChairman(conferenceStatus.getChairman());
                meeting.setIfUpMode(conferenceStatus.getIfUpMode());
                meeting.setMultiPicCtrlMode(conferenceStatus.getMultiPicCtrlMode());
                meeting.setMaxPicNum(conferenceStatus.getMaxPicNum());
                meeting.setCurPicNum(conferenceStatus.getCurPicNum());
                Meeting meeting1 = this.get(meeting.getId());
                meeting.setMeetingType(2);
                if(null != meeting1 && StringUtil.isNotEmpty( meeting1.getId())){
                    BeanUtils.copyProperties(meeting, meeting1);
                    meeting.setCreateBy(meeting1.getCreateBy());
                    meeting.setCreateName(meeting1.getCreateName());
                    meeting.setCreateCompanyId(meeting1.getCreateCompanyId());
                    meeting.setCreateCompanyName(meeting1.getCreateCompanyName());
                    meeting.setCreateOrgId(meeting1.getCreateOrgId());
                    meeting.setCreateOrgName(meeting1.getCreateOrgName());
                    meeting.setMeetingStatus(2);
                    this.update(meeting1);
                }else {
                    meeting.setIsSend(1);
                    meeting.setRemindTime("2,3,4");
                    meeting.setCreateBy("1");
                    meeting.setCreateName("管理员[系统]");
                    this.save(meeting);
                }
                // 3.同步终端信息
                List<ConfNode> confNodeList = zteManager.getConfNodeList(conferenceStatus.getConferenceIdentifier(), -1, -1);
                for (ConfNode confNode :  confNodeList){
                    int countPlace = meetingDao.countMeetingPlaceByMeetingIdAndTerminalId(conferenceStatus.getConferenceIdentifier(), confNode.getTerId());
                    if(countPlace == 0){
                        QueryWrapper<BizSiteParamEx> exQueryWrapper = new QueryWrapper<>();
                        exQueryWrapper.eq("TERMINAL_ID_", confNode.getTerId());
                        List<BizSiteParamEx> bizSiteParamExes = bizSiteParamExManager.list(exQueryWrapper);
                        if(null != bizSiteParamExes && bizSiteParamExes.size() > 0){
                            BizSiteParamEx bizSiteParamEx = bizSiteParamExes.get(0);
                            MeetingPlace meetingPlace = new MeetingPlace();
                            meetingPlace.setMeetingId(meeting.getId());
                            meetingPlace.setPlaceId(bizSiteParamEx.getId());
                            meetingPlace.setPlaceName(bizSiteParamEx.getName());
                            meetingPlaceDao.insert(meetingPlace);
                        }
                    }
                }
            }

        }

    }



    /**
     * 同步将来预定的会议
     * @return
     */
    @Override
    @Transactional
    public void synConferenceReserved() {

        // 1. 调用中兴查询将来会议信息,同步将来会议信息
        List<ConferenceSimpleInfo> conferenceInfoList = zteManager.getConferenceReservedList();
        if(null != conferenceInfoList && conferenceInfoList.size() > 0){
            List meetingList = new ArrayList(conferenceInfoList.size());
            for (ConferenceSimpleInfo conferenceStatus : conferenceInfoList){
                // 2. 同步会议信息
                Meeting meeting = new Meeting();
                BeanUtils.copyProperties(conferenceStatus, meeting);
                Calendar calendar = conferenceStatus.getStartTime();
                LocalDateTime startTime = LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
                meeting.setId(conferenceStatus.getConferenceIdentifier());
                meeting.setStartTime(startTime);
                int duration = conferenceStatus.getDuration();
                LocalDateTime endTime = startTime.plusMinutes(duration);
                LocalDateTime nowTime = LocalDateTime.now();
                Duration nowDuration = Duration.between(nowTime, startTime);
                long nowMillis = nowDuration.toMillis();
                if (nowTime.isAfter(startTime) || nowTime.isEqual(meeting.getStartTime()) || nowMillis < (1000*30)){
                    meeting.setMeetingStatus(2);
                }else{
                    meeting.setMeetingStatus(1);
                }
                meeting.setEndTime(endTime);
                meeting.setTheme(conferenceStatus.getConferenceName());
                meeting.setContent(conferenceStatus.getConferenceName());
                meeting.setConferenceNumber(conferenceStatus.getConferenceNumber());
                Meeting meeting1 = this.get(meeting.getId());
                meeting.setMeetingType(2);
                if(null != meeting1 && StringUtil.isNotEmpty( meeting1.getId())){
                    meeting.setCreateBy(meeting1.getCreateBy());
                    meeting.setCreateName(meeting1.getCreateName());
                    meeting.setCreateCompanyId(meeting1.getCreateCompanyId());
                    meeting.setCreateCompanyName(meeting1.getCreateCompanyName());
                    meeting.setCreateOrgId(meeting1.getCreateOrgId());
                    meeting.setCreateOrgName(meeting1.getCreateOrgName());
                    BeanUtils.copyProperties(meeting, meeting1);
                    this.update(meeting1);
                }else {
                    meeting.setIsSend(1);
                    meeting.setRemindTime("2,3,4");
                    meeting.setCreateBy("1");
                    meeting.setCreateName("管理员[系统]");
                    this.save(meeting);
                }
                // 3.同步终端信息
                List<ConfNode> confNodeList = zteManager.getConfNodeList(conferenceStatus.getConferenceIdentifier(), -1, -1);
                for (ConfNode confNode :  confNodeList){
                    int countPlace = meetingDao.countMeetingPlaceByMeetingIdAndTerminalId(conferenceStatus.getConferenceIdentifier(), confNode.getTerId());
                    if(countPlace == 0){
                        QueryWrapper<BizSiteParamEx> exQueryWrapper = new QueryWrapper<>();
                        exQueryWrapper.eq("TERMINAL_ID_", confNode.getTerId());
                        List<BizSiteParamEx> bizSiteParamExes = bizSiteParamExManager.list(exQueryWrapper);
                        if(null != bizSiteParamExes && bizSiteParamExes.size() > 0){
                            BizSiteParamEx bizSiteParamEx = bizSiteParamExes.get(0);
                            MeetingPlace meetingPlace = new MeetingPlace();
                            meetingPlace.setMeetingId(meeting.getId());
                            meetingPlace.setPlaceId(bizSiteParamEx.getId());
                            meetingPlace.setPlaceName(bizSiteParamEx.getName());
                            meetingPlaceDao.insert(meetingPlace);
                        }
                    }
                }
            }

        }

    }


    @Override
    @Transactional
    public String insertMeetingVo(MeetingDTO dto) {
        try {

            if (dto.getMeetingType() == 2) {
                //测试环境下注释中兴调用，注释掉就可以在测试环境进行测试,自己生成一次会议ID模拟视频会议返回的会议ID
//                dto.setId(CommonUtil.createGUID());
                CreateConferenceResponse result = zteManager.sendMeeting(dto);
                if (null != result && null != result.getResult() && "200".equals(result.getResult())) {
                    dto.setId(result.getConferenceIdentifier());
                } else {
                    return result.getResult();
                }
            }else {
                // 设置会议编号
                dto.setConferenceNumber(sysIdentityManager.nextId("hybh"));
            }
            String userName = baseContext.getCurrentUserName();
            if (StringUtils.isEmpty(dto.getTheme())) dto.setTheme(userName + "的无主题会议");
            Meeting meeting = new Meeting();
            BeanUtils.copyProperties(dto, meeting);
            // 设置会议状态，如果开始时间大于等于当前时间则设置为进行中，否则为未开始
            LocalDateTime nowTime = LocalDateTime.now();
            LocalDateTime startTime = meeting.getStartTime();
            Duration duration = Duration.between(nowTime, startTime);
            //相差的分钟数
            long minutes = duration.toMinutes();

            if (nowTime.isAfter(startTime) || nowTime.isEqual(startTime) || minutes == 0) {
                meeting.setMeetingStatus(2);
            } else {
                meeting.setMeetingStatus(1);
            }

            meeting.setCreateBy(baseContext.getCurrentUserId());
            meeting.setCreateName(userName);
            meeting.setRotationStatus(1);
            int result = meetingDao.insert(meeting);
            if (result <= 0) return result + "";

            List<MeetingUser> users = dto.getUsers();
            //判断是否选择了分组
//            List<String> userCodes = dto.getUserCodes();
            List<MeetingUser> users1 =new ArrayList<>();
//            List<String> noGroupIds=new ArrayList<>();
//            ArrayList<String> userAllIds = new ArrayList<>();

            //先加入没有分组的人
            if (null != users && users.size() > 0) {
                for (MeetingUser user : users) {
                    if (null != user.getUserName() && !"".equals(user.getUserName())) {
                        user.setMeetingId(meeting.getId());
                        user.setSignInStatus(1);
                        user.setSignOutStatus(1);
                        user.setSignInType(2);
//                        userAllIds.add(user.getUserId());
                        users1.add(user);
                    }
                }
                meetingUserManager.saveBatch(users1);
            }
                for (MeetingPlace place : dto.getPlaces()) {
                    place.setMeetingId(meeting.getId());
                    meetingPlaceDao.insert(place);
                }
                //保存投票
                if (dto.getTopics().size() > 0) {
                    for (BizMeetingTopic topic : dto.getTopics()) {
                        topic.setMeetingId(meeting.getId());
                        bizMeetingVoteManager.createVote(topic);
                    }
                }
                //保存会议文件
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(dto.getFiles())) {
                    List<String> list = Arrays.asList(dto.getFiles().split(","));
                    for (String fileId : list) {
                        BizMeetingAccessory accessory = meetingAccessoryManager.getById(fileId);
                        accessory.setSourceId(meeting.getId());
                        meetingAccessoryManager.updateById(accessory);
                    }

                }
                // 发送会议预约微信提醒
                this.sendMsg(meeting, 1);
                sendMsg(meeting, 4);

                return result + "";
            }catch(Exception e){
                e.printStackTrace();
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return "";
            }
        }


    @Override
    @Transactional
    public int updateMeetingVo(MeetingDTO dto) {
        Meeting meeting = new Meeting();
        BeanUtils.copyProperties(dto,meeting);
        // 设置会议状态，如果开始时间大于等于当前时间则设置为进行中，否则为未开始
        Long startTime = meeting.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        Long nowTime = new Date().getTime();
        if(nowTime >= startTime){
            meeting.setMeetingStatus(2);
        }else {
            meeting.setMeetingStatus(1);
        }
        int result = meetingDao.updateById(meeting);
        Map<String,Object> map = new HashMap<>();
        map.put("MEETING_ID_",meeting.getId());
        meetingUserDao.deleteByMap(map);
        meetingPlaceDao.deleteByMap(map);


        List<MeetingUser> users = dto.getUsers();
        //判断是否选择了分组
//            List<String> userCodes = dto.getUserCodes();
        List<MeetingUser> users1 =new ArrayList<>();

        //先加入没有分组的人
        if(null != users  && users.size() > 0){
            for (MeetingUser user : users){
                if(null != user.getUserName() && !"".equals(user.getUserName())) {

                    user.setMeetingId(meeting.getId());
                    user.setSignInStatus(1);
                    user.setSignOutStatus(1);
                    user.setSignInType(2);
                    users1.add(user);
                }
            }
            meetingUserManager.saveBatch(users1);
        }

        for (MeetingPlace place : dto.getPlaces()){
            place.setMeetingId(meeting.getId());
            meetingPlaceDao.insert(place);
        }
        this.sendMsg(meeting,3);
        //如果是视频会议，还应该调用中兴修改预约会议
        return result;
    }


    /**
     * 延长会议时间
     * @param meetingId
     * @param minutes
     * @return
     */
    @Override
    @Transactional
    public String delayMeeting(String meetingId, int meetingType,int minutes) {

        if (meetingType == 2) {

            ProlongConferenceResponse result = zteManager.prolongConference(meetingId,minutes);
            if (null != result && null != result.getResult() && "200".equals(result.getResult())) {
                //延长完成
            } else {
                return result.getResult();
            }
        }
        //修改系统中会议时间
        Meeting meeting = meetingDao.selectById(meetingId);
        LocalDateTime endTime = meeting.getEndTime();
        meeting.setEndTime(endTime.plusMinutes(minutes));
        this.update(meeting);
        return "1";
    }

    List<MeetingUser> findUserName(String meetingId){
        if (StringUtils.isEmpty(meetingId)) return null;
        return meetingDao.findUserName(meetingId);
    }

    List<MeetingPlace> findPlaceName(String meetingId){
        if (StringUtils.isEmpty(meetingId)) return null;
        return meetingDao.findPlaceName(meetingId);
    }

    List<MeetingPlace> findPlaceNameByDeptID(String meetingId, String deptId){
        if (StringUtils.isEmpty(meetingId)) return null;
        return meetingDao.findPlaceNameByDeptID(meetingId, deptId);
    }


    public void sendMsg(Meeting meeting,Integer type){
        List<MeetingUser> meetingUserList = meetingDao.findWxUserId(meeting.getId());
        if(null != meetingUserList && meetingUserList.size() > 0){
            List<String> userId = meetingUserList.stream().map(e->e.getAccount()).collect(Collectors.toList());
            if (userId.size()<=0) return;
            List<MeetingPlace> places = findPlaceName(meeting.getId());
            List<String> name = places.stream().map(d ->d.getPlaceName()).collect(Collectors.toList());
            // 如果是预约提醒则不循环发送
            if(1 == type){
                toduSend(meeting, type,  StringUtils.join(userId.toArray(),"|"), name);
            }else {
                for (MeetingUser user : meetingUserList){
                    // 反馈状态，1：准时参加会议，2：推迟参加会议，3：不能参加会议 4委托他人参会
                    String feedBack = user.getFeedBack();
                    // 如果反馈为不能参加会议
                    if("3".equalsIgnoreCase(feedBack)){
                        continue;
                    }
                    if("4".equalsIgnoreCase(feedBack)){
                        continue;
                    }
                    String account = user.getAccount();
                    // 通过账号查询组织ID
                    String currentDeptId = ContextUtil.getCurrentDeptIdByAccount(account);
                    // 通过组织ID过滤会场名称
                    if(StringUtils.isNotBlank(currentDeptId)){
                        List<MeetingPlace> placesByDeptId = findPlaceNameByDeptID(meeting.getId(), currentDeptId);
                        if(null != placesByDeptId && placesByDeptId.size() > 0){
                            List<String> placesByDeptIdList = placesByDeptId.stream().map(d -> d.getPlaceName()).collect(Collectors.toList());
                            toduSend(meeting, type,  account, placesByDeptIdList);
                        }else {
                            toduSend(meeting, type,  account, name);
                        }
                    }else {
                        toduSend(meeting, type,  account, name);
                    }
                }
            }
        }
    }

    /**
     * 做发送动作通知到企业微信
     * @param meeting 会议信息
     * @param type 消息类型
     * @param userId 发送通知企业微信ID,多个使用 | 隔开
     * @param name  会议室名称
     */
    public void toduSend(Meeting meeting,Integer type, String userId, List<String> name){
        List<DictModel> hylx = sysDictionaryManager.queryDictListItemsByCode("hylx");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd HH:mm");
        SysExternalUnite entity = sysExternalUniteDao.getOneByType("weChatWork");
        if(com.artfess.base.util.BeanUtils.isEmpty(entity)){
            throw new RuntimeException("查无此集成信息");
        }
        if (com.artfess.base.util.BeanUtils.isEmpty(meeting)) return;

        String meetingType = "现场会议";
        meetingType = BizUtils.getDicValueByCode(hylx, meeting.getMeetingType());
        String msg ;
        String meetingRoom = meeting.getMeetingType()==1?org.apache.commons.lang3.StringUtils.join(name,","):
                "本科室视频会议室";
        JSONObject jsonStr = new JSONObject();
        switch (type){
            case 1:
                // 会议预约成功通知
                jsonStr.put("title","会议预约成功");
                String description = "<div class=\"gray\">会议类型："+meetingType+"</div>" +
                        "<div class=\"gray\">会议主题："+meeting.getTheme()+"</div>" +
                        "<div class=\"gray\">会议时间："+formatter.format(meeting.getStartTime())+"</div>" +
                        "<div class=\"gray\">会议地点："+ meetingRoom+"</div>" +
                        "<div class=\"gray\">会议内容："+meeting.getContent()+"</div>"+
                        "<div class=\"gray\">备注："+(StringUtils.isNotBlank(meeting.getRemark())?meeting.getRemark():"")+"</div>";
                jsonStr.put("description",description);
                jsonStr.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+BizUtil.APPID +
                        "&redirect_uri=" + BizUtil.SYSTEM_URL + "/pages/mobile/fvue/qywxOauth%3FmeetingId%3D"+meeting.getId()
                        +"&response_type=code&scope=snsapi_base&state=STATE&agentid="+BizUtil.AGENTID+"#wechat_redirect");
                jsonStr.put("btntxt","查看详情");
                break;
            case 2:
                // 取消会议通知
                jsonStr.put("title","会议取消通知");
                String des = "<div class=\"highlight\">关于【" + meeting.getTheme() + "】的会议已取消</div>" +
                        "<div class=\"gray\">会议类型："+meetingType+"</div>" +
                        "<div class=\"gray\">会议主题："+meeting.getTheme()+"</div>" +
                        "<div class=\"gray\">会议时间："+formatter.format(meeting.getStartTime())+"</div>" +
                        "<div class=\"gray\">会议地点："+ meetingRoom+"</div>" +
                        "<div class=\"gray\">会议内容："+meeting.getContent()+"</div>"+
                        "<div class=\"gray\">备注："+(StringUtils.isNotBlank(meeting.getRemark())?meeting.getRemark():"")+"</div>";

                jsonStr.put("description",des);
                jsonStr.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+BizUtil.APPID +
                        "&redirect_uri=" + BizUtil.SYSTEM_URL + "/pages/mobile/fvue/qywxOauth%3FmeetingId%3D"+meeting.getId()
                        +"&response_type=code&scope=snsapi_base&state=STATE&agentid="+BizUtil.AGENTID+"#wechat_redirect");
                jsonStr.put("btntxt","查看详情");

                break;
            case 3:
                // 会议变更通知
                jsonStr.put("title","会议变更通知");
                String desc = "<div class=\"gray\">会议类型："+meetingType+"</div>" +
                        "<div class=\"gray\">会议主题："+meeting.getTheme()+"</div>" +
                        "<div class=\"gray\">变更后时间："+formatter.format(meeting.getStartTime())+"</div>" +
                        "<div class=\"gray\">会议地点："+ meetingRoom+"</div>" +
                        "<div class=\"gray\">会议内容："+meeting.getContent()+"</div>"+
                        "<div class=\"gray\">备注："+(StringUtils.isNotBlank(meeting.getRemark())?meeting.getRemark():"")+"</div>";

                jsonStr.put("description",desc);
                jsonStr.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+BizUtil.APPID +
                        "&redirect_uri=" + BizUtil.SYSTEM_URL + "/pages/mobile/fvue/qywxOauth%3FmeetingId%3D"+meeting.getId()
                        +"&response_type=code&scope=snsapi_base&state=STATE&agentid="+BizUtil.AGENTID+"#wechat_redirect");
                jsonStr.put("btntxt","查看详情");
                break;
            default:
                jsonStr.put("title","会议通知");
                String description1 ="<div class=\"gray\">会议类型："+meetingType+"</div>" +
                        "<div class=\"gray\">会议主题："+meeting.getTheme()+"</div>" +
                        "<div class=\"gray\">会议时间："+formatter.format(meeting.getStartTime())+"</div>" +
                        "<div class=\"gray\">会议地点："+ meetingRoom+" </div>" +
                        "<div class=\"gray\">会议内容："+meeting.getContent()+"</div>"+
//                        "<div class=\"gray\">备注："+(StringUtils.isNotBlank(meeting.getRemark())?meeting.getRemark():"")+"</div>"+
                        "<div class=\"highlight\">    注意：请于会议开始前10分钟进入会议室扫码签到，收到会议通知后请及时反馈是否准时参会。☛可点击此处进行反馈☚ </div>";
                jsonStr.put("description",description1);
                jsonStr.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+BizUtil.APPID +
                        "&redirect_uri=" + BizUtil.SYSTEM_URL + "/pages/mobile/fvue/qywxOauth%3FmeetingId%3D"+meeting.getId()
                        +"&response_type=code&scope=snsapi_base&state=STATE&agentid="+BizUtil.AGENTID+"#wechat_redirect");
                jsonStr.put("btntxt","查看详情☜");
        }
        try {
            String touser = userId;
            JSONObject params = new JSONObject();
            // 如果是预约通知，就发送给会议创建人
            if(1 == type){
                if(org.apache.commons.lang3.StringUtils.isNotBlank(meeting.getCreateBy())){
                    CommonResult<JsonNode> result = uCFeignService.getUserById(meeting.getCreateBy());
                    if(com.artfess.base.util.BeanUtils.isNotEmpty(result)){
                        JsonNode userNode = result.getValue();
                        String account = JsonUtil.getString(userNode, "account");
                        params.put("touser",account);
                    }
                }
            }else {
                params.put("touser",touser);
            }
            params.put("msgtype","textcard");
            params.put("agentid",entity.getAgentId());
            params.put("textcard",jsonStr);
            String str = params.toString();
            String url = WeChatWorkConsts.getSendMsgUrl();
            String resultJson = HttpUtil.sendHttpsRequest(url, params.toString(), "POST");
            JsonNode result = JsonUtil.toJsonNode(resultJson);
            String errcode = result.get("errcode").asText();
            log.debug(errcode);
            if ("0".equals(errcode)) {
                log.debug(touser+"推送消息成功");
            }
        }catch (Exception e){
            log.error("服务器异常，app推送消息失败："+ ExceptionUtils.getStackTrace(e));
//            throw new RuntimeException("推送消息失败");
            e.printStackTrace();
        }
    }


    /**
     * 委托参会发送信息
     * @param meeting
     * @param userName 委托人名称
     * @param entrustId 被委托人
     * @param entrustName 被委托人名称
     */
    @Override
    public void toEntrustSend(Meeting meeting,String userName,String entrustId,String entrustName){
        List<DictModel> hylx = sysDictionaryManager.queryDictListItemsByCode("hylx");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd HH:mm");
        SysExternalUnite entity = sysExternalUniteDao.getOneByType("weChatWork");
        if(com.artfess.base.util.BeanUtils.isEmpty(entity)){
            throw new RuntimeException("查无此集成信息");
        }
        if (com.artfess.base.util.BeanUtils.isEmpty(meeting)) return;

        String meetingType = "现场会议";
        meetingType = BizUtils.getDicValueByCode(hylx, meeting.getMeetingType());

        String meetingRoom = meeting.getMeetingType()==1?org.apache.commons.lang3.StringUtils.join(entrustName,","):
                "本科室视频会议室";
        JSONObject jsonStr = new JSONObject();
        jsonStr.put("title","会议预约成功");
        String description = "<div class=\"gray\">会议类型："+meetingType+"</div>" +
                "<div class=\"gray\">会议主题："+meeting.getTheme()+"</div>" +
                "<div class=\"gray\">会议时间："+formatter.format(meeting.getStartTime())+"</div>" +
                "<div class=\"gray\">会议地点："+ meetingRoom+"</div>" +
                "<div class=\"gray\">会议内容："+meeting.getContent()+"</div>"+
                "<div class=\"gray\">备注：由"+userName+"委托参加"+"</div>";
        jsonStr.put("description",description);
        jsonStr.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+BizUtil.APPID +
                "&redirect_uri=" + BizUtil.SYSTEM_URL + "/pages/mobile/fvue/qywxOauth%3FmeetingId%3D"+meeting.getId()
                +"&response_type=code&scope=snsapi_base&state=STATE&agentid="+BizUtil.AGENTID+"#wechat_redirect");
        jsonStr.put("btntxt","查看详情");

        try {

            JSONObject params = new JSONObject();
            params.put("touser",entrustId);
            params.put("msgtype","textcard");
            params.put("agentid",entity.getAgentId());
            params.put("textcard",jsonStr);

            String url = WeChatWorkConsts.getSendMsgUrl();
            String resultJson = HttpUtil.sendHttpsRequest(url, params.toString(), "POST");
            JsonNode result = JsonUtil.toJsonNode(resultJson);
            String errcode = result.get("errcode").asText();
            log.debug(errcode);
            if ("0".equals(errcode)) {
                log.debug(entrustId+"推送消息成功");
            }
        }catch (Exception e){
            log.error("服务器异常，app推送消息失败："+ ExceptionUtils.getStackTrace(e));
            e.printStackTrace();
        }
    }

    @Override
    @org.springframework.transaction.annotation.Transactional
    public String updateStatus(String id, Integer status) {
        Meeting meeting = meetingDao.selectById(id);
        if(null == meeting){
            return "0";
        }
        Integer meetingType = meeting.getMeetingType();
        // 视频会议，同时取消中兴会议
        if(2 == meetingType){
            // 会议状态，1：未开始，2：进行中，3：已结束，4：取消会议
            //测试环境下注释中兴调用
            if (3 == status){
                String zteResult = zteManager.endMeeting(id);
                if (!"1".equals(zteResult)){
                    return zteResult;
                }
            }
            if (4 == status){
                String zteResult = zteManager.cancelConferenceReserved(id);
                if (!"1".equals(zteResult)){
                    return zteResult;
                }
            }
        }
        if(4 == status){
            sendMsg(meeting, 2);
        }
        meetingDao.updateStatus(id, status);
        return "1";
    }


    @Override
    public String updateStatusOver(Meeting meeting, Integer status) {
        if(null == meeting){
            return "0";
        }
        Integer meetingType = meeting.getMeetingType();
        // 视频会议，同时取消中兴会议
        if(2 == meetingType){
            // 会议状态，1：未开始，2：进行中，3：已结束，4：取消会议
            //测试环境下注释中兴调用
            if (3 == status){
                String zteResult = zteManager.endMeeting(meeting.getId());
                if (!"1".equals(zteResult)){
                    System.out.println((String.format("结束会议结果：%s", zteResult)));
//                    return zteResult;
                }
            }
            if (4 == status){
                String zteResult = zteManager.cancelConferenceReserved(meeting.getId());
                if (!"1".equals(zteResult)){
                    return zteResult;
                }
            }
        }
        if(4 == status){
            sendMsg(meeting, 2);
        }
        //结束会议时 已签到并且未签退的人员签退时间改为【已签退】，签退时间填写当前时间
        if(3 == status){
            QueryWrapper<MeetingUser> queryWrapper =new QueryWrapper<>();
            queryWrapper.eq("MEETING_ID_",meeting.getId());
            queryWrapper.eq("SIGN_IN_STATUS_",0);
            List<MeetingUser> list = meetingUserManager.list(queryWrapper);

            if(null != list &&  list.size() > 0){
                for (MeetingUser user : list) {
                    user.setSignOutStatus(0);
                    user.setSignInType(2);
                    user.setLastExitDate(LocalDateTime.now());
                }
                meetingUserManager.saveOrUpdateBatch(list);
            }
        }
        meetingDao.updateStatus(meeting.getId(), status);
        return "1";
    }

    @Override
    @org.springframework.transaction.annotation.Transactional(rollbackFor =Exception.class)
    public String endMeeting(String id) {
        Meeting meeting = meetingDao.selectById(id);

        //结束会议只能是管理员和会议创建人才能结束
        IUser user= ContextUtil.getCurrentUser();
        //创建人ID
        String createBy = meeting.getCreateBy();
        boolean admin = user.isAdmin();

        if(!admin &&  !createBy.equals(user.getUserId())){
            throw new BaseException("结束会议只能由管理员或会议创建人结束");
        }


        if (2==meeting.getMeetingType()){
            String zteResult = zteManager.endMeeting(id);
            if (!"1".equals(zteResult)){
                return zteResult;
            }
        }
        meeting.setMeetingStatus(3);
        meeting.setEndTime(LocalDateTime.now());
        meetingDao.updateById(meeting);
        return "1";
    }

    @Override
    public String quiet(String id, String placeId) {
        /*
        BizSiteParamEx bizSiteParamEx = bizSiteParamExManager.getById(placeId);
        if (bizSiteParamEx==null || org.apache.commons.lang3.StringUtils.isEmpty(bizSiteParamEx.getDeviceStatusId())){
            return "0";
        }
        BizTerminal bizTerminal = bizTerminalManager.getById(bizSiteParamEx.getDeviceStatusId());
        if (bizTerminal==null) {
            return "0";
        }
         */
        return zteManager.quiet(id, placeId, true);
    }

    @Override
    public String cancelQuiet(String id, String placeId) {
        /*
        BizSiteParamEx bizSiteParamEx = bizSiteParamExManager.getById(placeId);
        if (bizSiteParamEx==null || org.apache.commons.lang3.StringUtils.isEmpty(bizSiteParamEx.getDeviceStatusId())) return "0";
        BizTerminal bizTerminal = bizTerminalManager.getById(bizSiteParamEx.getDeviceStatusId());
        if (bizTerminal==null) {
            return "0";
        }

         */
        return zteManager.cancelQuiet(id, placeId, true);
    }

    @Override
    public String connect(String id, String placeIds) {
        String[] placeIdsArr = null;
        if(org.apache.commons.lang3.StringUtils.isNotBlank(placeIds)){
            placeIdsArr = placeIds.split(",");
        }
//        List<String> places = Arrays.asList(placeIdsArr);
        /*
        String[] terids = new String[places.size()];
        for (int i = 0;i<places.size();i++){
            BizSiteParamEx bizSiteParamEx = bizSiteParamExManager.getById(places.get(i));
            if (bizSiteParamEx==null || org.apache.commons.lang3.StringUtils.isEmpty(bizSiteParamEx.getDeviceStatusId())) return "0";
            BizTerminal bizTerminal = bizTerminalManager.getById(bizSiteParamEx.getDeviceStatusId());
            if (bizTerminal==null) return "0";
            terids[i]=bizTerminal.getId();
        }
         */
        if(null != placeIdsArr && placeIdsArr.length > 0){
            for (String placeId : placeIdsArr){
                String[] param = new String[]{placeId};
                String result = zteManager.connect(id, param, false);
                if (!"1".equals(result)) {
                    return result;
                }
            }

        }
//        return zteManager.connect(id, placeIdsArr, false);
        return "1";
    }

    @Override
    public String disconnect(String id, String placeIds) {
        String[] placeIdsArr = placeIds.split(",");
        List<String> places = Arrays.asList(placeIdsArr);
        /*
        String[] terids = new String[places.size()];
        for (int i = 0;i<places.size();i++){
            BizSiteParamEx bizSiteParamEx = bizSiteParamExManager.getById(places.get(i));
            if (bizSiteParamEx==null || org.apache.commons.lang3.StringUtils.isEmpty(bizSiteParamEx.getDeviceStatusId())) return "0";
            BizTerminal bizTerminal = bizTerminalManager.getById(bizSiteParamEx.getDeviceStatusId());
            if (bizTerminal==null) return "0";
            terids[i]=bizTerminal.getId();
        }
         */
        return zteManager.disconnect(id, placeIdsArr);
    }

    @Override
    public ParticipantStatusV2[] participantStatusV2(String id) {
        ParticipantStatusV2[] statusV2s = zteManager.participantStatusV2(id);
        return statusV2s;
    }

    @Override
    public String inviteParticipant(String id, String placeIds) {
        List<String> places = Arrays.asList(placeIds.split(","));
        String result = "0";
        for (int i = 0;i<places.size();i++){
            QueryWrapper<BizSiteParamEx> bizSiteQueryWrapper = new QueryWrapper<>();
            bizSiteQueryWrapper.eq("TERMINAL_ID_",places.get(i));
            List<BizSiteParamEx> bizSiteParamExList = bizSiteParamExManager.list(bizSiteQueryWrapper);
            if(null != bizSiteParamExList && bizSiteParamExList.size() > 0){
                BizSiteParamEx bizSiteParamEx = bizSiteParamExList.get(0);
                Participant participant = new Participant();
                BeanUtils.copyProperties(bizSiteParamEx, participant);
                result = zteManager.inviteParticipant(id, participant);
            }

            QueryWrapper<BizTerminal> terminalQueryWrapper = new QueryWrapper<>();
            terminalQueryWrapper.eq("TERMINAL_ID_", places.get(i));
            List<BizTerminal> bizTerminalList = bizTerminalManager.list(terminalQueryWrapper);
            if(null != bizTerminalList && bizTerminalList.size() > 0){
                BizTerminal bizTerminal = bizTerminalList.get(0);
                Participant participant = new Participant();
                BeanUtils.copyProperties(bizTerminal, participant);
                participant.setTerminalIdentifier(places.get(i));
                result = zteManager.inviteParticipant(id, participant);
            }

        }
        return result;
    }

    @Override
    public Sha1VO getSha1(String url) {
        try {
            String ticket = null;
            if (ObjectUtils.isEmpty(redisUtil.get("ticket"))){
                String ticketUrl = WeChatWorkConsts.getTicketUrl();
                String resultJson = HttpUtil.sendHttpsRequest(ticketUrl, null, "GET");
                JsonNode result = JsonUtil.toJsonNode(resultJson);
                String errcode = result.get("errcode").asText();
                if ("0".equals(errcode)){
                    ticket = result.get("ticket").asText();
                    redisUtil.set("ticket",ticket,3000);
                }
            }else {
                ticket = redisUtil.get("ticket").toString();
            }
            String noncestr = getRandomString(16);
            String timestamp =String.valueOf(System.currentTimeMillis()/1000);
            String str = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;
            String sha1 = Sha1.encode(str);
            Sha1VO vo = new Sha1VO();
            vo.setSignature(sha1);
            vo.setTimestamp(timestamp);
            vo.setNonceStr(noncestr);
            System.out.println("*****************"+ticket);
            return vo;
        }catch (Exception e){
            e.printStackTrace();
            return new Sha1VO();
        }
    }

    public static String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

}
