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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.telephone.EduTelephone;
import com.yida.data.common.core.entity.telephone.EduTelephoneBlack;
import com.yida.data.common.core.entity.telephone.EduTelephoneCard;
import com.yida.data.common.core.entity.telephone.EduTelephoneCardMeal;
import com.yida.data.common.core.entity.telephone.EduTelephoneFamily;
import com.yida.data.common.core.entity.telephone.EduTelephoneMsg;
import com.yida.data.common.core.entity.telephone.EduTelephonePeriod;
import com.yida.data.common.core.entity.telephone.EduTelephonePrice;
import com.yida.data.common.core.entity.telephone.EduTelephoneRecord;
import com.yida.data.device.dto.telephone.PhoneCdataDTO;
import com.yida.data.device.telephone.constant.PhoneConstant;
import com.yida.data.device.telephone.mapper.EduTelephoneBlackMapper;
import com.yida.data.device.telephone.mapper.EduTelephoneCardMealMapper;
import com.yida.data.device.telephone.mapper.EduTelephoneFamilyMapper;
import com.yida.data.device.telephone.mapper.EduTelephoneMsgMapper;
import com.yida.data.device.telephone.mapper.EduTelephonePriceMapper;
import com.yida.data.device.telephone.service.EduTelephoneCardService;
import com.yida.data.device.telephone.service.EduTelephonePeriodService;
import com.yida.data.device.telephone.service.EduTelephoneRecordService;
import com.yida.data.device.telephone.service.EduTelephoneService;
import com.yida.data.device.telephone.service.PhoneService;
import com.yida.data.device.telephone.util.BalanceUtil;

import org.springframework.stereotype.Service;

import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@AllArgsConstructor
public class PhoneServiceImpl implements PhoneService {
    private final EduTelephoneService eduTelephoneService;
    private final EduTelephoneBlackMapper eduTelephoneBlackMapper;
    private final EduTelephoneCardService eduTelephoneCardService;
    private final EduTelephoneRecordService eduTelephoneRecordService;
    private final EduTelephoneFamilyMapper eduTelephoneFamilyMapper;
    private final EduTelephoneMsgMapper eduTelephoneMsgMapper;
    private final EduTelephonePriceMapper eduTelephonePriceMapper;
    private final EduTelephoneCardMealMapper eduTelephoneCardMealMapper;
    private final RedisService redisService;
    private final EduTelephonePeriodService eduTelephonePeriodService;

    @Override
    public String authen(String sn, String iccid) {
        log.info("话机认证，imei:[{}],iccid:[{}]", sn, iccid);
        String res = PhoneConstant.FAIL;
        EduTelephone telephone = eduTelephoneService.getOne(Wrappers.lambdaQuery(new EduTelephone())
                .eq(EduTelephone::getImei, sn));
        // 话机不存在或话机未在线
        if (telephone == null || telephone.getRunStatus() == 1) {
            return PhoneConstant.FAIL;
        }
        // 话机设置了通话时间段且当前未在时间段内
        LocalDateTime now = LocalDateTime.now();
        List<EduTelephonePeriod> periodList = eduTelephonePeriodService
                .list(Wrappers.lambdaQuery(new EduTelephonePeriod())
                        .eq(EduTelephonePeriod::getTelephoneId, telephone.getId()));
        if (CollUtil.isNotEmpty(periodList)) {
            for (EduTelephonePeriod period : periodList) {
                // 在某个区间内   跳出循环
                if (period.getStartTime().isBefore(now) && period.getEndTime().isAfter(now)) {
                    break;
                }
                return PhoneConstant.FAIL;
            }
        }
        // 设置了最大通话时长   且已达上限
        if (telephone.getMonthMaxLen() != 0
                && telephone.getTotalCallTime() / 60 + (telephone.getTotalCallTime() % 60 > 0 ? 1 : 0) == telephone.getMonthMaxLen()) {
            return PhoneConstant.FAIL + "|" + HexUtil.encodeHexStr(StrUtil.bytes("话机时长已达上限", Charset.forName("GB2312")));

        }
        return PhoneConstant.SUCCESS;
    }

    @Override
    public void heartbeat(String sn, String iccid) {
        log.info("接收心跳，imei:[{}]", sn);
        redisService.set(CachePrefixConstant.PHONE_ALIVE + sn, sn, 60L);
    }

    @Override
    public String cdata(String sn, String type, Integer start, PhoneCdataDTO dto) {
        log.info("数据接收，type:[{}]", type);
        String res = null;
        switch (type) {
            case PhoneConstant.TYPE_FAMILY:
                res = readFamily(dto.getCardno(), start);
                break;
            case PhoneConstant.TYPE_PRICE:
                res = readPrice(sn, dto);
                break;
            case PhoneConstant.TYPE_RECORD:
                res = saveRecord(sn, dto);
                break;
        }
        return res;
    }

    @Override
    public String getMsg(String cardNo) {
        log.info("读取消息，[{}]", cardNo);
        StringBuilder stringBuilder = new StringBuilder();
        EduTelephoneMsg newMsg = eduTelephoneMsgMapper.findNewMsg(cardNo, 0);
        if (newMsg != null) {
            stringBuilder
                    .append(newMsg.getId())
                    .append(",")
                    .append(HexUtil.encodeHexStr(StrUtil.bytes(newMsg.getMessage(), Charset.forName(
                            "GB2312"))));
            return stringBuilder.toString();
        }
        return "0";
    }

    @Override
    public void readMsg(Long msgId) {
        log.info("留言已读，[{}]", msgId);
        EduTelephoneMsg msg = new EduTelephoneMsg();
        msg.setId(msgId);
        msg.setIsRead(1);
        eduTelephoneMsgMapper.updateById(msg);
    }

    /**
     * 查询亲情号码
     *
     * @param cardno
     * @param start
     * @return
     */
    private String readFamily(String cardno, Integer start) {
        log.info("查询亲情电话，cardno:[{}],start:[{}]", cardno, start);
        StringBuilder res = new StringBuilder();
        if (start == null) {
            // 查询所有电话
            List<EduTelephoneFamily> families = eduTelephoneFamilyMapper.listFamily(cardno);
            if (CollUtil.isNotEmpty(families)) {
                for (EduTelephoneFamily family : families) {
                    res.append(family.getPhone());
                    if (StrUtil.isNotBlank(family.getRelation())) {
                        res.append("|").append(HexUtil.encodeHexStr(StrUtil.bytes(family.getRelation(), Charset.forName(
                                "GB2312"))));
                    }
                    res.append(",");
                }
            } else {
                return PhoneConstant.NONE;
            }
        } else if (start == 0) {
            // 查询所有电话
            List<EduTelephoneFamily> families = eduTelephoneFamilyMapper.listFamily(cardno);
            res.append(families.size()).append("@");
            if (CollUtil.isNotEmpty(families)) {
                for (EduTelephoneFamily family : families) {
                    res.append(family.getPhone());
                    if (StrUtil.isNotBlank(family.getRelation())) {
                        res.append("|").append(HexUtil.encodeHexStr(StrUtil.bytes(family.getRelation(), Charset.forName(
                                "GB2312"))));
                    }
                    res.append(",");
                }
            } else {
                return PhoneConstant.NONE;
            }
        } else {
            // 分页查询电话
            IPage<EduTelephoneFamily> iPage = eduTelephoneFamilyMapper.listFamilyPage(new Page(start, 4), cardno);
            res.append(iPage.getTotal()).append("@");
            if (CollUtil.isNotEmpty(iPage.getRecords())) {
                for (EduTelephoneFamily family : iPage.getRecords()) {
                    res.append(family.getPhone());
                    if (StrUtil.isNotBlank(family.getRelation())) {
                        res.append("|").append(HexUtil.encodeHexStr(StrUtil.bytes(family.getRelation(), Charset.forName(
                                "GB2312"))));
                    }
                    res.append(",");
                }
            } else {
                return PhoneConstant.NONE;
            }
        }
        log.info("res:[{}]", res);
        return res.toString();
    }

    /**
     * 获取费率
     *
     * @param sn
     * @param dto
     * @return
     */
    private String readPrice(String sn, PhoneCdataDTO dto) {
        log.info("获取费率，cardno:[{}]", dto.getCardno());
        StringBuilder stringBuilder = new StringBuilder();
        Integer mode, balance, rate;
        EduTelephoneCard card = eduTelephoneCardService.getOne(Wrappers.lambdaQuery(new EduTelephoneCard())
                .eq(EduTelephoneCard::getCardNo, dto.getCardno()));
        if (card == null || card.getStatus() == 1) {
            stringBuilder.append("0");
        } else {
            EduTelephone telephone = eduTelephoneService.getOne(Wrappers.lambdaQuery(new EduTelephone())
                    .eq(EduTelephone::getImei, sn));
            //查询话机是否禁用  呼叫号码是否在黑名单
            if (telephone == null || telephone.getRunStatus() == 1) {
                stringBuilder.append("4");
            } else {
                // 查询是否在黑名单中
                List<EduTelephoneBlack> blackList = eduTelephoneBlackMapper.selectList(Wrappers.lambdaQuery(new EduTelephoneBlack())
                        .eq(EduTelephoneBlack::getTelephoneId, telephone.getId()));
                if (CollUtil.isNotEmpty(blackList)) {
                    List<String> blackPhone = blackList.stream().map(x -> x.getPhone()).collect(Collectors.toList());
                    if (blackPhone.contains(dto.getPhone())) {
                        stringBuilder.append("8");
                    }
                }
                // 查询话机当月通话总时长
                // 查询话机当次通话最大通话时长
                // 话机未限制最大通话时长
                Integer maxMinute = telephone.getMonthMaxLen() > 0
                        ? telephone.getMonthMaxLen() - Long.valueOf(
                        telephone.getTotalCallTime() / 60 + (telephone.getTotalCallTime() % 60 > 0 ? 1 : 0)
                ).intValue() : -1;
                Integer nowMaxMinute = Integer.min(maxMinute, telephone.getTimeMaxLen());
                // 查询是否有套餐
                mode = 1;
                rate = 1;
                if (eduTelephoneCardMealMapper.selectCount(Wrappers.lambdaQuery(new EduTelephoneCardMeal())
                        .eq(EduTelephoneCardMeal::getStudentId, card.getStudentId())
                        .ge(EduTelephoneCardMeal::getEndTime, LocalDateTime.now())
                        .le(EduTelephoneCardMeal::getStartTime, LocalDateTime.now())) > 0) {
                    balance = nowMaxMinute;
                } else {
                    // 查询费率
                    EduTelephonePrice price = eduTelephonePriceMapper.selectById(card.getPriceId());
                    Double balanceValue = BalanceUtil.decode(card.getBalance());
                    Double v = balanceValue / price.getPrice();
                    balance = nowMaxMinute >= 0 ? Integer.min(v.intValue(), nowMaxMinute) : v.intValue();
                }
                // 分钟数为0 即余额不足
                if (balance == 0) {
                    return stringBuilder
                            .append("16")
                            .append(",")
                            .append(HexUtil.encodeHexStr(StrUtil.bytes("余额不足", Charset.forName("GB2312")))).toString();
                } else if (balance == -1) {
                    // 分钟数为-1  有套餐且话机未限制   任打
                    rate = 0;
                    balance = 0;
                }
                // 未添加其他错误信息   正常拨号
                if (stringBuilder.length() == 0) {
                    stringBuilder.append("1");
                }
                stringBuilder.append(",").append(mode).append(",").append(balance).append(",").append(rate);
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 保存通话记录
     *
     * @param sn
     * @param dto
     * @return
     */
    private String saveRecord(String sn, PhoneCdataDTO dto) {
        log.info("保存通话记录，cardno:[{}]", dto.getCardno());
        EduTelephoneRecord record = new EduTelephoneRecord();
        EduTelephoneCard card = eduTelephoneCardService.getOne(Wrappers.lambdaQuery(new EduTelephoneCard())
                .eq(EduTelephoneCard::getCardNo, dto.getCardno()));
        EduTelephone telephone = eduTelephoneService.getOne(Wrappers.lambdaQuery(new EduTelephone())
                .eq(EduTelephone::getImei, sn));
        if (telephone != null) {
            record.setTelephoneId(telephone.getId());
            telephone.setTotalCallTime(telephone.getTotalCallTime() + dto.getSecond());
        }
        record.setImei(sn);
        record.setCardId(card.getId());
        record.setCardNo(card.getCardNo());
        record.setStudentName(card.getStudentName());
        record.setCalling(dto.getPhoneNumber());
        record.setCallDuration(dto.getSecond());
        record.setCallDate(dto.getStarttime());
        eduTelephoneRecordService.save(record);
        // 计算消费
        if (eduTelephoneCardMealMapper.selectCount(Wrappers.lambdaQuery(new EduTelephoneCardMeal())
                .eq(EduTelephoneCardMeal::getStudentId, card.getStudentId())
                .ge(EduTelephoneCardMeal::getEndTime, dto.getStarttime())
                .le(EduTelephoneCardMeal::getStartTime, dto.getStarttime())) == 0) {
            EduTelephonePrice price = eduTelephonePriceMapper.selectOne(Wrappers.lambdaQuery(new EduTelephonePrice())
                    .eq(EduTelephonePrice::getId, card.getPriceId()));
            int minute = record.getCallDuration() / 60 + (record.getCallDuration() % 60 == 0 ? 0 : 1);
            if (minute > 0) {
                Double balance = BalanceUtil.decode(card.getBalance());
                double newBalance = balance - minute * price.getPrice();
                card.setBalance(BalanceUtil.encode(newBalance));
                eduTelephoneCardService.updateById(card);
            }
        }
        eduTelephoneService.updateById(telephone);
        return PhoneConstant.SUCCESS;
    }
}
