package com.bcxin.tenant.open.domains.dtos;

import com.bcxin.tenant.open.document.domains.documents.RdCompanyDocument;
import com.bcxin.tenant.open.document.domains.documents.RdCompanyDocument$;
import com.bcxin.tenant.open.domains.BillPaymentRuleConfig;
import com.bcxin.tenant.open.domains.entities.OrgPurseTransactionEntity;
import com.bcxin.tenant.open.domains.entities.RoomUserEntity;
import com.bcxin.tenant.open.domains.utils.TencentConstants;
import com.bcxin.tenant.open.domains.views.TencentCallbackLogView;
import com.bcxin.tenant.open.infrastructures.components.IdWorker;
import com.bcxin.tenant.open.infrastructures.components.JsonProvider;
import com.bcxin.tenant.open.infrastructures.enums.CommunicatedType;
import com.bcxin.tenant.open.infrastructures.enums.DeskType;
import com.bcxin.tenant.open.infrastructures.enums.DispatchReasonType;
import com.bcxin.tenant.open.infrastructures.enums.PointChangeType;
import com.bcxin.tenant.open.infrastructures.exceptions.ArgumentTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.BadTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.NotSupportTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.RetryableTenantException;
import com.redis.om.spring.search.stream.EntityStream;
import com.redis.om.spring.search.stream.SearchStream;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

@Getter
public class RoomCommunicatedGroupDTO {
    private static final Logger logger = LoggerFactory.getLogger(RoomCommunicatedGroupDTO.class);
    private final Long logId;
    private final DeskType deskType;
    private final String roomId;
    private final Long eventType;
    private final String callerDevicePkId;
    private final String callerDeviceNo;
    private final String callerEmployeeId;
    private final String callerEmployeeName;
    private final String callerCompanyName;

    /**
     * 是否由调用支付此次调度
     * 比如: 内保单位调用保安公司的保安人员, 由内保单位来支付联动值; 产生的调度记录也挂在内保单位中
     */
    private final boolean callerPayTheBill;

    private final String callerCompanyId;

    private final String callerOrgInstitutional;

    private final Long beginEventMsTs;
    private final Long endEventMsTs;

    private final DispatchReasonType referenceType;

    private final String referenceNumber;


    public Timestamp getBeginTime() {
        Date bt = new Date(this.getBeginEventMsTs());

        return Timestamp.from(bt.toInstant());
    }

    public Timestamp getEndTime() {
        Date et = new Date(this.getEndEventMsTs());

        return Timestamp.from(et.toInstant());
    }


    @Setter
    private Collection<JoinRoomUserDto> joinRoomUsers;
    @Setter
    private Collection<AudioVideoLogDto> audioVideoLogs;
    @Setter
    private Collection<NoAnswerRoomUserRecordDto> noAnswerRoomUsers;

    /**
     * 有视频就按视频来算
     * @return
     */
    public CommunicatedType getCommunicatedType() {
        if (CollectionUtils.isEmpty(this.getAudioVideoLogs())) {
            return CommunicatedType.Audio;
        }

        return this.getAudioVideoLogs().stream().filter(ii -> ii.getCommunicatedType() == CommunicatedType.Video)
                .map(ii -> ii.getCommunicatedType())
                .findFirst().orElse(CommunicatedType.Audio);
    }

    public RoomCommunicatedGroupDTO(
            DeskType deskType,
            Long logId,
                                    Long eventType,
                                    String roomId,
                                    String callerDevicePkId,
                                    String callerDeviceNo,
                                    String callerEmployeeId,
                                    String callerEmployeeName,
                                    String callerCompanyId,
                                    String callerCompanyName,
                                    Long beginEventMsTs,
                                    Long endEventMsTs,
                                    DispatchReasonType referenceType,
                                    String referenceNumber,
            boolean callerPayTheBill,
            String callerOrgInstitutional
                                    ) {
        this.eventType = eventType;
        this.deskType= deskType;
        this.logId = logId;
        this.roomId = roomId;
        this.callerDeviceNo = callerDeviceNo;
        this.callerEmployeeId = callerEmployeeId;
        this.callerEmployeeName = callerEmployeeName;
        this.callerCompanyId = callerCompanyId;
        this.beginEventMsTs = beginEventMsTs;
        this.endEventMsTs = endEventMsTs;
        this.callerCompanyName = callerCompanyName;
        this.callerDevicePkId = callerDevicePkId;

        this.referenceType = referenceType;
        this.referenceNumber = referenceNumber;
        this.noAnswerRoomUsers = new ArrayList<>();

        this.callerPayTheBill = callerPayTheBill;
        this.callerOrgInstitutional = callerOrgInstitutional;
    }

    public static RoomCommunicatedGroupDTO create(
            JsonProvider jsonProvider,
            DeskType deskType,
            String roomId,
            DispatchReasonType referenceType,
            String referenceNumber,
            Collection<TencentCallbackLogView> roomLifeCycleLogs,
            Collection<RoomUserEntity> roomUsers,
            EntityStream entityStream,
            BillPaymentRuleConfig billPaymentRuleConfig
            ) {
        Optional<TencentCallbackLogView> startRoomOptional =
                roomLifeCycleLogs.stream()
                        .filter(ii -> ii.getRoomId().equalsIgnoreCase(roomId) &&
                                TencentConstants.filterStartRoom(ii.getEventType()))
                        .findFirst();
        Optional<TencentCallbackLogView> endRoomOptional = roomLifeCycleLogs
                .stream().filter(ii ->
                        ii.getRoomId().equalsIgnoreCase(roomId) &&
                                TencentConstants.filterEndRoom(ii.getEventType()))
                .findFirst();

        if (!startRoomOptional.isPresent() || !endRoomOptional.isPresent()) {
            throw new RetryableTenantException("该房间数据暂时不完整, 请稍等后再重试;");
        }

        TencentCallbackLogView startRoom = startRoomOptional.get();
        TencentCallbackLogView endRoom = endRoomOptional.get();
        RoomUserEntity roomUser = roomUsers.stream()
                .filter(ii -> org.apache.commons.lang3.StringUtils.equalsIgnoreCase(ii.getTencentUserId(), startRoom.getTencentUserId()))
                .findFirst().orElse(null);

        if (roomUser == null) {
            throw new BadTenantException(String.format("非预期异常: 找不到该用户(%s)信息", startRoom.getTencentUserId()));
        }

        SearchStream<RdCompanyDocument> companyDocumentSearchStream =
                entityStream.of(RdCompanyDocument.class);

        RdCompanyDocument callerCompanyDocument =
                companyDocumentSearchStream
                        .filter(RdCompanyDocument$.ID.eq(roomUser.getOrganizationId()))
                        .findFirst().orElse(null);
        if (callerCompanyDocument == null) {
            throw new ArgumentTenantException(String.format("异常数据: 找不到调度方(%s)的企业信息数据", roomUser.getOrganizationId()));
        }

        boolean callerPayTheBill = billPaymentRuleConfig.isPaymentOwner(
                callerCompanyDocument.getInstitutional(),
                callerCompanyDocument.getSuperviseRegionCode());

        RoomCommunicatedGroupDTO roomCommunicatedGroup =
                new RoomCommunicatedGroupDTO(
                        deskType,
                        startRoom.getId(),
                        startRoom.getEventType(),
                        startRoom.getRoomId(),
                        startRoom.getRoomId(),
                        startRoom.getTencentUserId(),
                        roomUser.getEmployeeId(),
                        roomUser.getEmployeeName(),
                        roomUser.getOrganizationId(),
                        roomUser.getOrganizationName(),
                        startRoom.getEventMsTs(jsonProvider),
                        endRoom.getEventMsTs(jsonProvider),
                        referenceType,
                        referenceNumber,
                        callerPayTheBill,
                        callerCompanyDocument.getInstitutional()
                );

        return roomCommunicatedGroup;
    }

    /**
     * 计算现有房间的所有人
     * @param joinRoomLogs
     */
    public void joinRooms(
            TencentCallbackLogView startRoomView,
            Collection<TencentCallbackLogView> joinRoomLogs,
            JsonProvider jsonProvider,
            Collection<RoomUserEntity> roomUsers) {
        if (CollectionUtils.isEmpty(joinRoomLogs)) {
            return;
        }

        Collection<String> joinUserIds =
                joinRoomLogs.stream()
                        .filter(ix -> StringUtils.hasLength(ix.getTencentUserId()))
                        .map(ix -> ix.getTencentUserId())
                        .distinct().collect(Collectors.toList());

        Collection<JoinRoomUserDto> joinRoomUsers
                = joinUserIds.stream().flatMap(ii -> {
            Collection<JoinRoomUserDto> joinUsers = new ArrayList<>();
            Collection<TencentCallbackLogView> enterRoomLogList = joinRoomLogs.stream().filter(ix ->
                            TencentConstants.filterEnterRoom(ix.getEventType()) && ix.getTencentUserId().equalsIgnoreCase(ii))
                    .collect(Collectors.toList());
            for (TencentCallbackLogView enterRoomLog : enterRoomLogList) {
                Optional<TencentCallbackLogView> exitRoomLogOptional = joinRoomLogs.stream().filter(ix ->
                        TencentConstants.filterExitRoom(ix.getEventType()) &&
                                ix.getTencentUserId().equalsIgnoreCase(enterRoomLog.getTencentUserId())
                                /**
                                 * 取出该人加入房间之后;第一次离开房间的时间
                                 */
                                && ix.getEventMsTs(jsonProvider).compareTo(enterRoomLog.getEventMsTs(jsonProvider)) > 0
                ).findFirst();

                if (!exitRoomLogOptional.isPresent()) {
                    throw new RetryableTenantException("未找到该用户信息");
                }

                TencentCallbackLogView exitRoomLog = exitRoomLogOptional.get();

                /**
                 * 找出匹配时间点和人的调度记录信息
                 * 降序; 找到时间最接近的那条数据
                 */
                Collection<RoomUserEntity> matchRoomUsers
                        = roomUsers.stream().filter(ic -> {
                            boolean flag = org.apache.commons.lang3.StringUtils.equalsIgnoreCase(ic.getTencentUserId(), enterRoomLog.getTencentUserId());

                            if (flag) {
                                long eventMsTs = enterRoomLog.getEventMsTs(jsonProvider);
                                Date eventDate = new Date(eventMsTs);
                                flag = ic.getCreatedTime().before(eventDate);
                            }
                            return flag;
                        })
                        .sorted(Comparator.comparing(RoomUserEntity::getCreatedTime).reversed())
                        .collect(Collectors.toList());

                RoomUserEntity selectedRoomUser = matchRoomUsers.stream().findFirst().orElse(null);

                /**
                 * 针对腾讯服务器那边返回的时间竟然比业务系统插入的时间小的问题，我们直接忽略并获取第一条
                 */
                if(selectedRoomUser==null) {
                    selectedRoomUser = roomUsers.stream().filter(ic -> {
                                boolean flag = org.apache.commons.lang3.StringUtils.equalsIgnoreCase(ic.getTencentUserId(), enterRoomLog.getTencentUserId());
                                return flag;
                            })
                            .sorted(Comparator.comparing(RoomUserEntity::getCreatedTime).reversed())
                            .findFirst().orElse(null);
                }

                if (selectedRoomUser == null) {
                    throw new BadTenantException(String.format("非预期数据, 找不到对应的邀请记录信息v2"));
                }

                JoinRoomUserDto joinRoomUserDto =
                        JoinRoomUserDto.create(
                                selectedRoomUser.getId(),
                                enterRoomLog.getTencentUserId(),
                                selectedRoomUser.getEmployeeId(),
                                selectedRoomUser.getEmployeeName(),
                                selectedRoomUser.getOrganizationName(),
                                enterRoomLog.getEventMsTs(jsonProvider),
                                exitRoomLog.getEventMsTs(jsonProvider),
                                selectedRoomUser.getOrganizationId(),
                                enterRoomLog.getTencentUserId().equalsIgnoreCase(startRoomView.getTencentUserId()),
                                selectedRoomUser.isSuperviseRole(),
                                selectedRoomUser.getCreatedTime(),
                                selectedRoomUser.getSecurityStationId(),
                                selectedRoomUser.getSecurityStationName(),
                                selectedRoomUser.getProjectId(),
                                selectedRoomUser.getProjectName()
                        );
                /**
                 * 解决用户断掉之后；重新在接听的问题
                 */
                /*
                if (!joinUsers.stream().anyMatch(ic -> ic.getEmployeeId().equalsIgnoreCase(selectedRoomUser.getEmployeeId()) &&
                        (ic.getBeginEventMsTs() != null && ic.getEndEventMsTs() != null && joinRoomUserDto.getBeginEventMsTs() != null &&
                                joinRoomUserDto.getEndEventMsTs() != null) &&
                        ic.getBeginEventMsTs().longValue() == joinRoomUserDto.getBeginEventMsTs().longValue() &&
                        ic.getEndEventMsTs().longValue() == joinRoomUserDto.getEndEventMsTs().longValue()
                )) {
                    joinUsers.add(joinRoomUserDto);
                }
                 */

                joinUsers.add(joinRoomUserDto);
            }

            return joinUsers.stream();
        }).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(this.getJoinRoomUsers())) {
            this.setJoinRoomUsers(joinRoomUsers);
        } else {
            Collection<JoinRoomUserDto> existsJoinRoomUsers = this.getJoinRoomUsers();
            existsJoinRoomUsers.addAll(joinRoomUsers);

            this.setJoinRoomUsers(existsJoinRoomUsers);
        }
    }

    /**
     * 在会议中加入音视频逻辑
     * 如果该会议有视频的话; 那么只要计算视频即可; 并且时间按照最早的来算
     * 如果该会议没有视频的话; 那么则直接计算音频即可; 并且收费的时候按照两倍进行计算
     * @param audioVideos
     * @param jsonProvider
     */
    public void addAudioVideoLogs(Collection<TencentCallbackLogView> audioVideos,
                                  JsonProvider jsonProvider) {
        if (CollectionUtils.isEmpty(audioVideos)) {
            return;
        }

        Collection<AudioVideoLogDto> audioVideoLogs = new ArrayList<>();

        /**
         * 开始计算音视频的联动值消耗
         */
        Collection<TencentCallbackLogView> startVideoAutoAssitLogs =
                audioVideos.stream().filter(ix -> TencentConstants.filterStartVideoAudioAssit(ix.getEventType()))
                        .collect(Collectors.toList());

        for (TencentCallbackLogView startCommunicated : startVideoAutoAssitLogs) {
            Optional<TencentCallbackLogView> endCommunicatedOptional = audioVideos.stream()
                    .filter(adv -> TencentConstants.filterMatchedStopVideoAudioAssit(startCommunicated.getEventType(), adv.getEventType())
                            && adv.getEventMsTs(jsonProvider) >= startCommunicated.getEventMsTs(jsonProvider) &&
                            adv.getTencentUserId().equals(startCommunicated.getTencentUserId())
                    )
                    .sorted((i1, i2) -> i2.getEventMsTs(jsonProvider).compareTo(i1.getEventMsTs(jsonProvider)))
                    .findFirst();

            Long endTime = this.getEndEventMsTs();
            if (endCommunicatedOptional.isPresent()) {
                endTime = endCommunicatedOptional.get().getEventMsTs(jsonProvider);
            }

            AudioVideoLogDto audioVideoLog =
                    AudioVideoLogDto.create(
                            startCommunicated.getId(),
                            startCommunicated.getEventType(),
                            startCommunicated.getEventMsTs(jsonProvider),
                            endTime, startCommunicated.getTencentUserId());

            audioVideoLogs.add(audioVideoLog);
        }

        Collection<AudioVideoLogDto> existsAudioVideoLogs = this.getAudioVideoLogs();
        if (existsAudioVideoLogs == null) {
            existsAudioVideoLogs = new ArrayList<>();
        }
        existsAudioVideoLogs.addAll(audioVideoLogs);

        if (CollectionUtils.isEmpty(existsAudioVideoLogs)) {
            return;
        }

        /**
         * 重新计算音视频的逻辑:
         * 1, 有视频; 则按照视频的时间来计算
         * 2, 无视频; 则按照调度的音频来进行计算
         */
        CommunicatedType communicatedType = CommunicatedType.Video;
        Optional<AudioVideoLogDto> selectedVideoLogOptional = existsAudioVideoLogs.stream()
                .filter(ix -> ix.getCommunicatedType() == CommunicatedType.Video)
                .min(Comparator.comparingLong(AudioVideoLogDto::getBeginEventMsTs));

        if (!selectedVideoLogOptional.isPresent()) {
            selectedVideoLogOptional =
                    existsAudioVideoLogs.stream().min(Comparator.comparingLong(AudioVideoLogDto::getBeginEventMsTs));
            communicatedType = CommunicatedType.Audio;
        }

        Long endEventMsTs =
                existsAudioVideoLogs.stream()
                        .map(ix -> ix.getEndEventMsTs())
                        .max(Comparator.comparingLong(Long::longValue))
                        .get();

        AudioVideoLogDto selectedVideoLog = selectedVideoLogOptional.get();
        AudioVideoLogDto computedAudioVideoLog =
                AudioVideoLogDto.createByComputed(
                        selectedVideoLog.getId(),
                        communicatedType,
                        selectedVideoLog.getBeginEventMsTs(),
                        endEventMsTs,
                        selectedVideoLog.deviceNo
                );
        this.setAudioVideoLogs(Collections.singleton(computedAudioVideoLog));
    }

    /**
     * 核对并添加人员到房间组
     * @param userRecords
     */
    @Deprecated
    public void checkAndAddNotAnswerRoomUserRecords(
            IdWorker idWorker,
            String selectedTencentUserId, Collection<RoomUserEntity> userRecords) {
        /**
         * 通过降序的方式来排序加入房间的时间
         */
        Collection<JoinRoomUserDto> selectedJoinRoomUsers =
                this.getJoinRoomUsers().stream()
                        .filter(ii -> ii.getDeviceNo().equalsIgnoreCase(selectedTencentUserId))
                        .sorted(Comparator.comparing(JoinRoomUserDto::getBeginTime))
                        .collect(Collectors.toList());

        /**
         * 未接听的情况; 计算联动值
         */
        Timestamp lastAnsweredBeginTime = null;
        if (selectedJoinRoomUsers.size() < userRecords.size()) {
            for (JoinRoomUserDto joinUser : selectedJoinRoomUsers) {
                final Timestamp selectedLastBeginTime = lastAnsweredBeginTime;

                /**
                 * 取排序中符合的区间数据
                 */
                Collection<RoomUserEntity> matchedRoomUsers
                        = userRecords.stream().filter(ii ->
                                ii.getTencentUserId().equalsIgnoreCase(joinUser.getDeviceNo()) &&
                                        (selectedLastBeginTime == null || ii.getCreatedTime().after(selectedLastBeginTime)) &&
                                        ii.getCreatedTime().before(ii.getCreatedTime()))
                        .sorted(Comparator.comparing(RoomUserEntity::getCreatedTime).reversed())
                        .collect(Collectors.toList());
                if (matchedRoomUsers.size() > 1) {
                    RoomUserEntity closedRoomUser = matchedRoomUsers.stream().findFirst().orElse(null);
                    if (closedRoomUser != null) {
                        Collection<NoAnswerRoomUserRecordDto> noAnswerRoomUserRecords =
                                matchedRoomUsers.stream()
                                        .filter(ii -> ii.getId() != closedRoomUser.getId())
                                        .map(ii ->
                                                NoAnswerRoomUserRecordDto.create(
                                                        ii.getId(),
                                                        ii.getRoomId(),
                                                        ii.getTencentUserId(),
                                                        ii.getEmployeeId(),
                                                        ii.getEmployeeName(),
                                                        ii.getOrganizationName(),
                                                        ii.getOrganizationId(),
                                                        ii.getCreatedTime(),
                                                        ii.getSecurityStationId(),
                                                        ii.getSecurityStationName(),
                                                        ii.getProjectId(),
                                                        ii.getProjectName()
                                                        )
                                        ).collect(Collectors.toList());

                        this.noAnswerRoomUsers.addAll(noAnswerRoomUserRecords);
                    }
                }

                lastAnsweredBeginTime = joinUser.getBeginTime();
            }

            /**
             * 最后一次接听之后创建的人员都属于未接听的人员
             */
            if (lastAnsweredBeginTime != null) {
                Collection<NoAnswerRoomUserRecordDto> noAnswerRoomUserRecords =
                        userRecords.stream()
                                .map(ii ->
                                        NoAnswerRoomUserRecordDto.create(
                                                ii.getId(),
                                                ii.getRoomId(),
                                                ii.getTencentUserId(),
                                                ii.getEmployeeId(),
                                                ii.getEmployeeName(),
                                                ii.getOrganizationName(),
                                                ii.getOrganizationId(),
                                                ii.getCreatedTime(),
                                                ii.getSecurityStationId(),
                                                ii.getSecurityStationName(),
                                                ii.getProjectId(),
                                                ii.getProjectName()
                                                )
                                ).collect(Collectors.toList());

                this.noAnswerRoomUsers.addAll(noAnswerRoomUserRecords);
            }
        }
    }


    public void addNoAnswerRoomUsers(IdWorker idWorker, Collection<RoomUserEntity> noAnsweredRoomUsers) {
        if (CollectionUtils.isEmpty(noAnsweredRoomUsers)) {
            return;
        }

        Collection<NoAnswerRoomUserRecordDto> noAnswerRoomUserRecords =
                noAnsweredRoomUsers.stream().map(ii -> {
                    return NoAnswerRoomUserRecordDto.create(
                            ii.getId(),
                            ii.getId(),
                            ii.getTencentUserId(),
                            ii.getEmployeeId(),
                            ii.getEmployeeName(),
                            ii.getOrganizationName(),
                            ii.getOrganizationId(),
                            ii.getCreatedTime(),
                            ii.getSecurityStationId(),
                            ii.getSecurityStationName(),
                            ii.getProjectId(),
                            ii.getProjectName()
                            );
                }).collect(Collectors.toList());

        if (this.getNoAnswerRoomUsers() == null) {
            this.setNoAnswerRoomUsers(new ArrayList<>());
        }

        this.noAnswerRoomUsers.addAll(noAnswerRoomUserRecords);
    }

    /**
     *  转化为交易数据
     * @return
     */
    public Collection<OrgPurseTransactionEntity> translate2Transactions() {
        return null;
    }

    @Getter
    public static class JoinRoomUserDto {
        private final long invitedUserRecordId;
        private final String id;
        private final String deviceNo;
        private final String employeeId;
        private final String employeeName;

        private final String companyName;

        private final Long beginEventMsTs;
        private final Long endEventMsTs;
        private final String domainId;

        private final boolean isCaller;

        private final boolean isSuperviseRole;

        private final Timestamp createdTime;

        private final String securityStationId;
        private final String securityStationName;
        private final String projectId;
        private final String projectName;


        public Timestamp getBeginTime() {
            Date bt = new Date(this.getBeginEventMsTs());

            return Timestamp.from(bt.toInstant());
        }

        public Timestamp getEndTime() {
            Date et = new Date(this.getEndEventMsTs());

            return Timestamp.from(et.toInstant());
        }

        public JoinRoomUserDto(
                long invitedUserRecordId,
                String deviceNo,
                String employeeId,
                String employeeName,
                String companyName,
                Long beginEventMsTs, Long endEventMsTs,
                String domainId, boolean isCaller,
                boolean isSuperviseRole,
                Timestamp createdTime,
                String securityStationId, String securityStationName, String projectId, String projectName) {
            this.deviceNo = deviceNo;
            this.employeeId = employeeId;
            this.employeeName = employeeName;
            this.beginEventMsTs = beginEventMsTs;
            this.endEventMsTs = endEventMsTs;
            this.domainId = domainId;
            this.isCaller = isCaller;
            this.securityStationId = securityStationId;
            this.securityStationName = securityStationName;
            this.projectId = projectId;
            this.projectName = projectName;
            this.id = UUID.randomUUID().toString();
            this.companyName = companyName;
            this.isSuperviseRole = isSuperviseRole;
            this.invitedUserRecordId = invitedUserRecordId;
            this.createdTime = createdTime;
        }

        public static JoinRoomUserDto create(
                long invitedUserRecordId,
                String deviceNo, String employeeId, String employeeName,String companyName, Long beginEventMsTs,
                                             Long endEventMsTs,String domainId, boolean isCaller,boolean isSuperviseRole,
                Timestamp createdTime,
                String securityStationId, String securityStationName, String projectId, String projectName) {
            return new JoinRoomUserDto(invitedUserRecordId, deviceNo, employeeId,
                    employeeName,companyName, beginEventMsTs, endEventMsTs, domainId,
                    isCaller,isSuperviseRole,createdTime, securityStationId, securityStationName, projectId, projectName);
        }
    }

    @Getter
    public static class AudioVideoLogDto {
        private final Long id;
        private final CommunicatedType communicatedType;
        private final Long beginEventMsTs;
        private final Long endEventMsTs;

        public Timestamp getBeginTime() {
            Date bt = new Date(this.getBeginEventMsTs());

            return Timestamp.from(bt.toInstant());
        }

        public Timestamp getEndTime() {
            Date et = new Date(this.getEndEventMsTs());

            return Timestamp.from(et.toInstant());
        }


        /**
         * 获取实际开始听取音视频的开始时间
         * @param roomUserDto
         * @return
         */
        public Timestamp getActuallyBeginJoinTime(JoinRoomUserDto roomUserDto) {
            assert roomUserDto != null;

            if (roomUserDto.getBeginEventMsTs() > this.getBeginEventMsTs()) {
                return roomUserDto.getBeginTime();
            } else {
                return this.getBeginTime();
            }
        }

        /**
         * 获取实际听取音视频的截至时间
         * @param roomUserDto
         * @return
         */
        public Timestamp getActuallyEndJoinTime(JoinRoomUserDto roomUserDto) {
            assert roomUserDto != null;

            if (roomUserDto.getEndEventMsTs() == null || roomUserDto.getEndEventMsTs() > this.getEndEventMsTs()) {
                return this.getEndTime();
            } else {
                return roomUserDto.getEndTime();
            }
        }

        /**
         * 判断加入房间的这个用户是否有接听到此音视频的信息
         * 用户加入的时候; 如果房间音视频调度未结束或者用户离开的时候音视频已经开始;
         * 那么表示
         * 该用户有听到音视频的信息
         * @param roomUserDto
         * @return
         */
        public boolean HasJoin(JoinRoomUserDto roomUserDto) {
            assert roomUserDto != null;

            return (roomUserDto.getBeginEventMsTs() <= this.getEndEventMsTs() || this.getEndEventMsTs() == null) ||
                    (roomUserDto.getEndEventMsTs() == null || roomUserDto.getEndEventMsTs() > this.getBeginEventMsTs());
        }

        private final String deviceNo;

        public AudioVideoLogDto(Long id,
                                CommunicatedType communicatedType, Long beginEventMsTs,
                                Long endEventMsTs, String deviceNo) {
            this.id = id;
            this.communicatedType = communicatedType;
            this.beginEventMsTs = beginEventMsTs;
            this.endEventMsTs = endEventMsTs;
            this.deviceNo = deviceNo;
        }

        public static AudioVideoLogDto create(Long id,
                                              Long eventType, Long beginEventMsTs, Long endEventMsTs, String deviceNo) {
            CommunicatedType communicatedType = CommunicatedType.Video;
            if(TencentConstants.EVENT_TYPE_START_AUDIO==eventType) {
                communicatedType = CommunicatedType.Audio;
            }else if(TencentConstants.EVENT_TYPE_START_VIDEO==eventType)
            {
                communicatedType = CommunicatedType.Video;
            }else {
                throw new NotSupportTenantException("不支持");
            }

            return new AudioVideoLogDto(id,communicatedType, beginEventMsTs, endEventMsTs, deviceNo);
        }

        public static AudioVideoLogDto createByComputed(Long id,
                                              CommunicatedType communicatedType, Long beginEventMsTs, Long endEventMsTs, String deviceNo) {
            return new AudioVideoLogDto(id, communicatedType, beginEventMsTs, endEventMsTs, deviceNo);
        }

        public PointChangeType  getChangeType()
        {
            switch (this.getCommunicatedType()) {
                case Audio -> {
                    return PointChangeType.AudioCost;
                }
                case Video -> {
                    return PointChangeType.VideoCost;
                }
                default -> {
                    throw new NotSupportTenantException(String.format("非法沟通方式:%s", this.getCommunicatedType()));
                }
            }
        }
    }

    @Getter
    public static class NoAnswerRoomUserRecordDto {
        private final long id;
        private final String deviceNo;
        private final String employeeId;
        private final String employeeName;
        private final String companyName;
        private final String domainId;
        private final Timestamp createdTime;
        /**
         * 作为
         */
        private final long referenceNumber;

        private final String securityStationId;

        private final String securityStationName;

        private final String projectId;

        private final String projectName;

        public NoAnswerRoomUserRecordDto(
                long id,
                long referenceNumber,
                String deviceNo,
                String employeeId, String employeeName,
                String companyName, String domainId,
                Timestamp createdTime,
                String securityStationId, String securityStationName, String projectId, String projectName) {
            this.id = id;
            this.deviceNo = deviceNo;
            this.employeeId = employeeId;
            this.employeeName = employeeName;
            this.companyName = companyName;
            this.domainId = domainId;
            this.createdTime = createdTime;
            this.referenceNumber = referenceNumber;
            this.securityStationId = securityStationId;
            this.securityStationName = securityStationName;
            this.projectId = projectId;
            this.projectName = projectName;
        }

        public static NoAnswerRoomUserRecordDto create(
                long id,
                long referenceNumber,
                String deviceNo, String employeeId, String employeeName,
                                                       String companyName, String domainId,
                                                       Timestamp createdTime,
                String securityStationId, String securityStationName, String projectId, String projectName) {
            return new NoAnswerRoomUserRecordDto(
                    id,
                    referenceNumber,
                    deviceNo, employeeId, employeeName, companyName, domainId, createdTime, securityStationId, securityStationName, projectId, projectName);
        }
    }
}
