package com.yida.data.device.telephone.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.attendance.enums.DeviceStateEnum;
import com.yida.data.common.core.entity.card.EduStudentCard;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.entity.telephone.*;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.utils.EnumUtils;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.device.dto.telephone.DevicePage;
import com.yida.data.device.dto.telephone.TelephoneDTO;
import com.yida.data.device.telephone.mapper.EduTelephoneMapper;
import com.yida.data.device.telephone.mapper.EduTelephoneRecordMapper;
import com.yida.data.device.telephone.service.EduTelephoneBlackService;
import com.yida.data.device.telephone.service.EduTelephonePeriodService;
import com.yida.data.device.telephone.service.EduTelephoneService;
import com.yida.data.device.telephone.util.BalanceUtil;
import com.yida.data.device.vo.OnlineCountVO;
import com.yida.data.device.vo.telephone.DeviceNumberVO;
import com.yida.data.device.vo.telephone.TelephoneVO;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.user.feign.RemoteStudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 亲情电话-话机管理 Service实现
 *
 * @author zhanghaijun
 * @date 2021-08-10 16:27:43
 */
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional
public class EduTelephoneServiceImpl extends ServiceImpl
    <EduTelephoneMapper, EduTelephone> implements EduTelephoneService {

    private final EduTelephoneRecordMapper eduTelephoneRecordMapper;
    private final RedisService redisService;
    private final EduTelephonePeriodService eduTelephonePeriodService;
    private final EduTelephoneBlackService eduTelephoneBlackService;
    private final RemoteStudentService remoteStudentService;
    private final RemoteDeptService remoteDeptService;
    private final CommonService commonService;

    /**
     * 话机列表分页查询
     *
     * @param page
     * @param onlineStatus
     * @param runStatus
     * @param iccIdAndiMei
     * @param name
     * @param currentUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DevicePage<TelephoneVO> telephoneList(DevicePage<TelephoneVO> page, String onlineStatus, String runStatus,
        String iccIdAndiMei, String name, CurrentUser currentUser,
        Long schoolId, String schoolName) throws NoSuchMethodException {
        LocalDateTime now = LocalDateTime.now();
        int month = now.getMonthValue();
        String start = now.getYear() + ":" + (month > 10 ? month : "0" + month) + ":01 00:00:00";

        List<Long> schoolIds = new ArrayList<>();
        // 查询关联学校信息
        List<Dept> deptList = this.remoteDeptService.getSchoolByArea(null, schoolName).getData();
        if (CollUtil.isNotEmpty(deptList)) {
            schoolIds = deptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
        } else {
            // 添加默认值，防止报错
            schoolIds.add(-1L);
        }
        DevicePage<TelephoneVO> devicePage = baseMapper.telephoneList(page, onlineStatus, runStatus, iccIdAndiMei,
            now, start, name, schoolIds, currentUser, schoolName);
        // 在线离线数量
        devicePage.setOnlineNumber((int) count(Wrappers.<EduTelephone>lambdaQuery()
            .eq(EduTelephone::getOnlineStatus, DeviceStateEnum.ONLINE_STATUS.getStatus())
            .in(EduTelephone::getSchoolId, schoolIds)));
        devicePage.setOfflineNumber((int) count(Wrappers.<EduTelephone>lambdaQuery()
            .eq(EduTelephone::getOnlineStatus, DeviceStateEnum.OFFLINE_STATUS.getStatus())
            .in(EduTelephone::getSchoolId, schoolIds)));
        if (CollUtil.isNotEmpty(devicePage.getRecords())) {
            for (TelephoneVO telephoneVO : devicePage.getRecords()) {
                telephoneVO.setSchoolName(commonService.getDept(telephoneVO.getSchoolId()).getDeptName());
            }
        }
        return devicePage;
    }

    /**
     * 修改电话在线状态
     *
     * @param online 话机将要更新成的状态 0-在线，1-不在线
     * @param imeis  存活的话机设备
     */
    @Override
    public void updatePhoneOnline(Integer online, Set<String> imeis) {
        baseMapper.updatePhoneOnline(online, imeis);
    }

    /**
     * 查询话机详情
     *
     * @param id
     * @return
     */
    @Override
    public TelephoneVO getByTelephoneId(Long id) {

        TelephoneVO telephoneVO = baseMapper.getByTelephoneId(id);
        EduTelephoneRecord eduTelephoneRecord = eduTelephoneRecordMapper.selectMaxRecord();
        List<EduTelephonePeriod> list = eduTelephonePeriodService.list(Wrappers.lambdaQuery(new EduTelephonePeriod())
            .eq(EduTelephonePeriod::getTelephoneId, id));
        List<EduTelephoneBlack> blacks = eduTelephoneBlackService.list(Wrappers.lambdaQuery(new EduTelephoneBlack())
            .eq(EduTelephoneBlack::getTelephoneId, id));
        EduTelephone eduTelephone = new EduTelephone();
        eduTelephone.setId(id);
        eduTelephone.setTotalCallTime(telephoneVO.getCallDuration());
        baseMapper.updateById(eduTelephone);
        telephoneVO.setMaxDate(eduTelephoneRecord.getCreateDate());
        telephoneVO.setPeriodList(list);
        telephoneVO.setBlackList(blacks);
        return telephoneVO;
    }

    /**
     * 查询家长对应学生列表
     *
     * @param parentId
     * @param schoolId
     * @return
     */
    @Override
    public List<EduTelephoneCard> getStudentList(Long parentId, Long schoolId) {
        List<EduStudent> students = remoteStudentService.listStudentByParent(parentId).getData();
        List<Long> studentIdList = students.stream().map(EduStudent::getId).collect(Collectors.toList());
        List<EduTelephoneCard> cardList = baseMapper.listStudent(LocalDateTime.now(), studentIdList);
        if (CollUtil.isNotEmpty(cardList)) {
            for (EduTelephoneCard card : cardList) {
                for (EduStudent student : students) {
                    if (card.getStudentId().equals(student.getId())) {
                        card.setAvatar(student.getAvatar());
                        card.setFamilyType(student.getFamilyType());
                        card.setBalanceValue(BalanceUtil.decode(card.getBalance()));
                        card.setBalance(null);
                    }
                }
            }
        }
        return cardList;
    }

    /**
     * 修改话机设置
     *
     * @param telephoneDTO
     */
    @Override
    public void updateTelephone(TelephoneDTO telephoneDTO) {
        // 设置单台话机
        if (telephoneDTO.getTelephoneId() != null) {
            EduTelephone phone = getById(telephoneDTO.getTelephoneId());
            // 删除原有数据
            eduTelephoneBlackService.remove(Wrappers.lambdaQuery(new EduTelephoneBlack())
                .eq(EduTelephoneBlack::getTelephoneId, phone.getId()));
            eduTelephonePeriodService.remove(Wrappers.lambdaQuery(new EduTelephonePeriod())
                .eq(EduTelephonePeriod::getTelephoneId, phone.getId()));
            // 保存新数据
            if (CollectionUtil.isNotEmpty(telephoneDTO.getBlacks())) {
                ArrayList<EduTelephoneBlack> blackList = new ArrayList<>();
                for (EduTelephoneBlack black : telephoneDTO.getBlacks()) {
                    black.setTelephoneId(phone.getId());
                    blackList.add(black);
                }
                eduTelephoneBlackService.saveOrUpdateBatch(blackList);
            }
            if (CollectionUtil.isNotEmpty(telephoneDTO.getPeriods())) {
                ArrayList<EduTelephonePeriod> periodList = new ArrayList<>();
                for (EduTelephonePeriod period : telephoneDTO.getPeriods()) {
                    period.setTelephoneId(phone.getId());
                    periodList.add(period);
                }
                eduTelephonePeriodService.saveBatch(periodList);
            }
            phone.setTimeMaxLen(telephoneDTO.getTimeMaxLen());
            phone.setMonthMaxLen(telephoneDTO.getMonthMaxLen());
            saveOrUpdate(phone);
            return;
        }

        // 批量设置
        List<EduTelephone> list = list(Wrappers.lambdaQuery(new EduTelephone())
            .in(EduTelephone::getSchoolId, telephoneDTO.getSchoolId()));
        if (CollUtil.isNotEmpty(list)) {
            // 删除原有黑名单与通话时间段
            List<Long> telephoneIds = list.stream().map(EduTelephone::getId).collect(Collectors.toList());
            eduTelephoneBlackService.remove(Wrappers.lambdaQuery(new EduTelephoneBlack())
                .in(EduTelephoneBlack::getTelephoneId, telephoneIds));
            eduTelephonePeriodService.remove(Wrappers.lambdaQuery(new EduTelephonePeriod())
                .in(EduTelephonePeriod::getTelephoneId, telephoneIds));
            List<EduTelephoneBlack> blacks = new ArrayList<>();
            List<EduTelephonePeriod> periods = new ArrayList<>();
            for (EduTelephone eduTelephone : list) {
                eduTelephone.setMonthMaxLen(telephoneDTO.getMonthMaxLen());
                eduTelephone.setTimeMaxLen(telephoneDTO.getTimeMaxLen());

                // 保存黑名单
                if (CollUtil.isNotEmpty(telephoneDTO.getBlacks())) {
                    for (EduTelephoneBlack black : telephoneDTO.getBlacks()) {
                        EduTelephoneBlack newBlack = new EduTelephoneBlack();
                        BeanUtils.copyProperties(black, newBlack);
                        newBlack.setTelephoneId(eduTelephone.getId());
                        blacks.add(newBlack);
                    }
                }
                // 保存通话时间段
                if (CollUtil.isNotEmpty(telephoneDTO.getPeriods())) {
                    for (EduTelephonePeriod period : telephoneDTO.getPeriods()) {
                        EduTelephonePeriod newPeriod = new EduTelephonePeriod();
                        newPeriod.setTelephoneId(eduTelephone.getId());
                        periods.add(newPeriod);
                    }
                }
            }
            saveOrUpdateBatch(list);
            // 保存
            eduTelephoneBlackService.saveOrUpdateBatch(blacks);
            eduTelephonePeriodService.saveOrUpdateBatch(periods);
        }
    }

    /**
     * 修改话机状态
     */
    @Override
    public void updateTelephoneStatus() {
        Set<String> alivePhone = redisService.keys(CachePrefixConstant.PHONE_ALIVE);

        Set<String> alivePhoneSn = CollUtil.isNotEmpty(alivePhone) ?
            alivePhone.stream().map(x -> x.substring(CachePrefixConstant.PHONE_ALIVE.length())).collect(Collectors.toSet())
            : null;
        if (CollUtil.isEmpty(alivePhoneSn)) {
            alivePhoneSn = new HashSet<String>() {{
                add("-1");
            }};
        }
        log.info("修改话机在线状态,alivePhoneSn:[{}]", alivePhoneSn);
        updatePhoneOnline(0, alivePhoneSn);
        updatePhoneOnline(1, alivePhoneSn);
    }

    /**
     * 话机设备数量统计
     *
     * @return com.yida.data.common.core.common.ResultBean<com.yida.data.attendance.vo.DeviceNumberVO>
     * @author ZYJ
     * @date 2021/10/9 15:17
     */
    @Override
    public ResultBean<DeviceNumberVO> findDeviceNumber() throws NoSuchMethodException {
        // 需要查询的学校id集合
        List<Long> schoolIds = new ArrayList<>();
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        // 获取登陆用户角色类型
        List<RoleEnum> roleList = new ArrayList<>();
        if (StringUtils.isNotBlank(Objects.requireNonNull(currentUser).getRolePerms())) {
            for (String rolePerm : Objects.requireNonNull(currentUser).getRolePerms().split(StringConstant.COMMA)) {
                // 获取登陆角色类型
                RoleEnum roleEnum = EnumUtils.valueOf(RoleEnum.class, rolePerm,
                    RoleEnum.class.getMethod("getValue"));
                if (Objects.nonNull(roleEnum)) {
                    roleList.add(roleEnum);
                }
            }
        }

        if (CollectionUtils.isNotEmpty(roleList)) {
            // 排序
            RoleEnum roleEnum = roleList.stream().sorted(Comparator.comparing(RoleEnum::getOrder))
                .collect(Collectors.toList()).get(0);
            // 代理商相关账号
            if (RoleEnum.ROLE_AGENT_ADMIN.equals(roleEnum) || RoleEnum.ROLE_AGENT_NORMAL.equals(roleEnum)) {
                List<Dept> deptList = remoteDeptService.getSchoolByArea(null, null).getData();
                if (CollUtil.isNotEmpty(deptList)) {
                    schoolIds = deptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
                }
            } else if (RoleEnum.ROLE_SCHOOL_PRINCIPAL.equals(roleEnum)) {
                // 学校负责人账号
                schoolIds.add(currentUser.getDeptId());
            } else {
                return ResultBean.buildSuccess(
                    DeviceNumberVO.builder()
                        .totalNumber(0L)
                        .onlineNumber(0L)
                        .offlineNumber(0L)
                        .build());
            }
        }
        // 查询不同状态考勤设备数量
        Long offlineNumber = this.baseMapper.findDeviceNumber(schoolIds, DeviceStateEnum.OFFLINE_STATUS.getStatus());
        Long onlineNumber = this.baseMapper.findDeviceNumber(schoolIds, DeviceStateEnum.ONLINE_STATUS.getStatus());
        return ResultBean.buildSuccess(
            DeviceNumberVO.builder()
                .totalNumber(offlineNumber + onlineNumber)
                .onlineNumber(onlineNumber)
                .offlineNumber(offlineNumber)
                .build()
        );
    }

    @Override
    public OnlineCountVO getOnlineDistrib(List<Long> schoolIds) {
        OnlineCountVO vo = new OnlineCountVO();
        if (CollUtil.isNotEmpty(schoolIds)) {
            List<EduTelephone> cardList = list(Wrappers.<EduTelephone>lambdaQuery().in(EduTelephone::getSchoolId, schoolIds)
                .select(EduTelephone::getOnlineStatus));
            Map<Integer, List<EduTelephone>> onlineGroup = cardList.stream()
                .collect(Collectors.groupingBy(EduTelephone::getOnlineStatus));
            vo.setOnlineNum(onlineGroup.getOrDefault(0, Collections.emptyList()).size());
            vo.setOfflineNum(onlineGroup.getOrDefault(1, Collections.emptyList()).size());
        }
        return vo;
    }
}
