package com.zd.chemical.service.impl;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.zd.chemical.domain.HxpCabinetlockLog;
import com.zd.chemical.domain.vo.*;
import com.zd.chemical.mapper.HxpCabinetlockLogMapper;
import com.zd.chemical.service.IHxpCabinetlockLogService;
import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.enums.LockTypeEnum;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.DateUtils;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.utils.StringUtils;
import com.zd.common.datascope.annotation.DataScope;
import com.zd.common.security.utils.SaveUtil;

import com.zd.common.swagger.config.AppListener;
import com.zd.system.api.camera.RemoteCameraService;
import com.zd.system.api.laboratory.CabinetV2Lock;
import com.zd.system.api.laboratory.RemoteLaboratoryService;
import com.zd.system.api.laboratory.RemoteSubQueryService;
import com.zd.system.api.laboratory.domain.CabinetLock;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zd.chemical.mapper.HxpCabinetMapper;
import com.zd.chemical.domain.HxpCabinet;
import com.zd.chemical.service.IHxpCabinetService;

/**
 * 化学品机柜管理信息Service业务层处理
 *
 * @author liubo
 * @date 2022-06-16
 */
@Service
public class HxpCabinetServiceImpl implements IHxpCabinetService {
    private static org.slf4j.Logger logger= LoggerFactory.getLogger(AppListener.class);

    @Autowired
    private HxpCabinetMapper hxpCabinetMapper;
    @Autowired
    private RemoteLaboratoryService remoteLaboratoryService;
    @Autowired
    private RemoteCameraService remoteCameraService;
    @Autowired
    private RemoteSubQueryService remoteSubQueryService;
    @Autowired
    private IHxpCabinetlockLogService cabinetlockLogService;
    @Autowired
    private HxpCabinetlockLogMapper cabinetlockLogMapper;

    /**
     * 查询化学品机柜管理信息
     *
     * @param id 化学品机柜管理信息主键
     * @return 化学品机柜管理信息
     */
    @Override
    public HxpCabinet selectHxpCabinetById(Long id) {
        return hxpCabinetMapper.selectHxpCabinetById(id);
    }

    /**
     * 查询化学品机柜管理信息列表
     *
     * @param hxpCabinetSearch 化学品机柜管理信息
     * @return 化学品机柜管理信息
     */
    @Override
    @DataScope(deptAlias = "st", userAlias = "ct", permi = PerPrefix.HXP_CABINET)
    public List <HxpCabinetVo> selectHxpCabinetList(HxpCabinetSearch hxpCabinetSearch) {
        List <HxpCabinetVo> hxpCabinetVos = hxpCabinetMapper.selectHxpCabinetList(hxpCabinetSearch);
        Function <List <HxpCabinetVo>, List <Long>> function = x -> x.parallelStream().map(HxpCabinetVo::getId).collect(Collectors.toList());
        Map<String,List <Long>> allMap = new HashMap();
        allMap.put("ids", function.apply(hxpCabinetVos));
        R <List <LinkedHashMap <String, String>>> cabinetLockList = remoteLaboratoryService.getHardwareByLockList(allMap);
        Predicate <R <List <LinkedHashMap <String, String>>>> predicate = b -> b.getData() != null && b.getData().size() > 0;
        if (predicate.test(cabinetLockList)) {
            List <HxpCabinetVo> cabinetVoList = Optional.ofNullable(hxpCabinetVos).orElseGet(Collections::emptyList).parallelStream()
                    .map(a -> {
                                Optional.ofNullable(cabinetLockList.getData()).orElseGet(Collections::emptyList)
                                        .stream().filter(b -> b.get("joinCabinetId").equals(a.getId() + "")).forEach(b -> a.getCabinetLockList().add(b));
                                return a;
                            }
                    ).sorted(Comparator.comparing(HxpCabinetVo::getCreateTime).reversed()).collect(Collectors.toList());
            return cabinetVoList;
        }
        return hxpCabinetVos;
    }

    /**
     * 新增化学品机柜管理信息
     *
     * @param hxpCabinet 化学品机柜管理信息
     * @return 结果
     */
    @Override
    public int insertHxpCabinet(HxpCabinet hxpCabinet) {
        try {
            R <Map<Object, Object>> data = remoteLaboratoryService.getCheckInfo(hxpCabinet.getSubId());
            if (data.getData() != null) {
                Map<Object, Object> subMap = data.getData();
                //生成机柜编号
                if (StringUtils.isNull(subMap.get("deptName"))) {
                    throw new ServiceException("生成编码错误，请检查实验室关联的学院是否正确！！");
                }
                String pinyin = generateNumber(subMap.get("deptName") + "");
                pinyin += subMap.get("room") + "-";
                hxpCabinet.setCabinetNum(synthesisNumber(pinyin).toString());
            }
        } catch (Exception e) {
            throw new ServiceException("生成编码错误，联系管理员！！");
        }

        //设置其他公共字段
        SaveUtil.setCommonAttr(hxpCabinet);
        return hxpCabinetMapper.insertHxpCabinet(hxpCabinet);
    }

    public String generateNumber(String china) {
        HanyuPinyinOutputFormat formart = new HanyuPinyinOutputFormat();
        formart.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        formart.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        formart.setVCharType(HanyuPinyinVCharType.WITH_V);
        char[] arrays = china.trim().toCharArray();
        String result = "";
        try {
            for (int i = 0; i < 2; i++) {
                char ti = arrays[i];
                if (Character.toString(ti).matches("[\\u4e00-\\u9fa5]")) { //匹配是否是中文
                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(ti, formart);
                    result += temp[0].substring(0, 1).toUpperCase();
                } else {
                    result += ti;
                }
            }
        } catch (BadHanyuPinyinOutputFormatCombination e) {
            e.printStackTrace();
        }

        return result;
    }

    public StringBuffer synthesisNumber(String pinyin) {
        HxpCabinet hxpCabinet = hxpCabinetMapper.selectHxpCabinetMaxById(pinyin);
        String cabinetNum;
        if (StringUtils.isNotNull(hxpCabinet)) {
            cabinetNum = hxpCabinet.getCabinetNum().substring(hxpCabinet.getCabinetNum().length() - 3);
            cabinetNum = (Integer.parseInt(cabinetNum) + 1) + "";
        } else {
            cabinetNum = "1";
        }
        StringBuffer jgNum = new StringBuffer();
        jgNum.append(pinyin);
        for (int i = 0; i < 3 - cabinetNum.length(); i++) {
            jgNum.append("0");
        }
        jgNum.append(cabinetNum);
        return jgNum;
    }

    /**
     * 修改化学品机柜管理信息
     *
     * @param hxpCabinet 化学品机柜管理信息
     * @return 结果
     */
    @Override
    public int updateHxpCabinet(HxpCabinet hxpCabinet) {
        hxpCabinet.setUpdateTime(DateUtils.getNowDate());
        hxpCabinet.setUpdateBy(SecurityUtils.getUsername());
        return hxpCabinetMapper.updateHxpCabinet(hxpCabinet);
    }

    /**
     * 批量删除化学品机柜管理信息
     *
     * @param ids 需要删除的化学品机柜管理信息主键
     * @return 结果
     */
    @Override
    public int deleteHxpCabinetByIds(Long[] ids) {
        return hxpCabinetMapper.deleteHxpCabinetByIds(ids);
    }

    /**
     * 删除化学品机柜管理信息信息
     *
     * @param id 化学品机柜管理信息主键
     * @return 结果
     */
    @Override
    public int deleteHxpCabinetById(Long id) {
        return hxpCabinetMapper.deleteHxpCabinetById(id);
    }


    /**
     * 查询机柜关联化学品数据统计列表
     *
     * @param hxpCabinetSearch 化学品机柜管理信息
     * @return 化学品机柜管理信息
     */
    @Override
    public List <HxpCabinetInclusionChemicalVo> getCabinetByChemical(HxpCabinetSearch hxpCabinetSearch) {
        //这里查询化学品统计的分页数据。
        List <HxpCabinetInclusionChemicalVo> inclusionChemicalVoList = hxpCabinetMapper.getCabinetByChemical(hxpCabinetSearch);

        //查询每个化学品对应的库存信息等。
        Optional.ofNullable(inclusionChemicalVoList).orElseGet(Collections::emptyList).stream()
                .forEach(a -> {
                    a.setLockId(hxpCabinetSearch.getLockId());
                    a.setUseStatus(hxpCabinetSearch.getUseStatus());
                    a.setSearchValue(hxpCabinetSearch.getSearchValue());
                    a.setHxpCabinetInclusionChemicalSonList(hxpCabinetMapper.getCabinetByChemicalDetail(a));
                });
        return inclusionChemicalVoList;
    }

    @Override
    public List<AioCabinetLockVo> queryCabinetLockList(AioCabinetLockVo aioCabinetLockVo) {
        return hxpCabinetMapper.queryCabinetLockList(aioCabinetLockVo);
    }

    @Override
    public AioSubInfoVo querySubInfo(Long subId) {
        return hxpCabinetMapper.querySubInfo(subId);
    }

    @Override
    public CabinetV2Lock openLock(AioCabinetLockVo aioCabinetLockVo) {
        // 第一版开锁流程
        // Map<String, Object> result = doLock(aioCabinetLockVo, 1);

        CabinetV2Lock cabinetV2Lock = doLockTwo(aioCabinetLockVo, 1);
        return cabinetV2Lock;
    }

    @Override
    public CabinetV2Lock closeLock(AioCabinetLockVo aioCabinetLockVo) {
        // 一版关锁流程
        // Map<String, Object> result = doLock(aioCabinetLockVo, 2);

        CabinetV2Lock result = doLockTwo(aioCabinetLockVo, 2);
        return result;
    }

    private CabinetV2Lock doLockTwo(AioCabinetLockVo aioCabinetLockVo, int type) {
        CabinetV2Lock result;
        if(LockTypeEnum.SYSTEM.equals(aioCabinetLockVo.getLockType()) && aioCabinetLockVo.getLockId() != null){
            result = hxpCabinetMapper.selectIpAddressByLockId(aioCabinetLockVo.getSubId(), aioCabinetLockVo.getLockId());
        }else {
            result = hxpCabinetMapper.selectByJoinId(aioCabinetLockVo.getJoinId());
        }

        if(result == null){
            throw new ServiceException("未查询到柜锁设置，操作失败！");
        }

        boolean success = false;
        String closeLockVideo = null;
        String msg = "";
        if (type == 1) {
            // 开锁
            // 1. 执行开锁命令
            R r = remoteSubQueryService.cabinetV2OpenLock(result);
            logger.info("柜锁开锁返回数值：" + r.getCode() + ";;;;" + r.getMsg());
            msg = r.getMsg();
            // 2. 判断执行状态
            if(r.getCode() == HttpStatus.SUCCESS){
                success = true;
                // 3. 调用录像功能
                remoteCameraService.startRecord(result.getIpAddress());
            }
        }else if(type == 2){
            // 关锁
            R r = remoteSubQueryService.cabinetV2CloseLock(result);
            logger.info("柜锁关锁返回数值：" + r.getCode() + ";;;;" + r.getMsg());
            msg = r.getMsg();
            // 判断执行状态
            if(r.getCode() == HttpStatus.SUCCESS){
                success = true;
                // 结束录像获取地址
                R r1 = remoteCameraService.stopRecord(result.getIpAddress());
                if(r1 != null && HttpStatus.SUCCESS == r1.getCode()){
                    logger.info("柜锁关闭获取录像地址：" + r1.getData());
                    closeLockVideo = r1.getData() + "";
                    success = true;
                }else {
                    logger.error("柜锁关闭获取摄像头录像失败：" + r.getMsg());
                }
            }
        }

        // 添加记录
        if(success){
            if(type == 1){
                HxpCabinetlockLog hxpCabinetlockLog = new HxpCabinetlockLog();
                hxpCabinetlockLog.setCabinetlockId(Long.parseLong(result.getHardwareId()));
                hxpCabinetlockLog.setUnLockTime(DateUtils.getNowDate());
                hxpCabinetlockLog.setOperationType(aioCabinetLockVo.getLockType().getCode());
                hxpCabinetlockLog.setCreateTime(DateUtils.getNowDate());
                hxpCabinetlockLog.setCreateBy(SecurityUtils.getUsername());
                cabinetlockLogService.insertHxpCabinetlockLog(hxpCabinetlockLog);

                result.setLockLogId(hxpCabinetlockLog.getId());
            }else if(type == 2){
                // 关锁之后要存储录像
//                HxpCabinetlockLog hxpCabinetlockLog = cabinetlockLogMapper.selectByLockId(aioCabinetLockVo.getSubId(), Integer.parseInt(result.getLockId()));
                HxpCabinetlockLog hxpCabinetlockLog = cabinetlockLogMapper.selectHxpCabinetlockLogById(aioCabinetLockVo.getLockLogId());
                result.setLockLogId(aioCabinetLockVo.getLockLogId());
                if(hxpCabinetlockLog != null){
                    if(LockTypeEnum.IN_STOCK.equals(aioCabinetLockVo.getLockType()) && aioCabinetLockVo.getStockId() != null){
                        logger.info("关锁绑定入库ID：" + aioCabinetLockVo.getStockId());
                        hxpCabinetlockLog.setStockId(aioCabinetLockVo.getStockId());
                    }
                    hxpCabinetlockLog.setCloseLockTime(DateUtils.getNowDate());
                    hxpCabinetlockLog.setCloseLockVideo(closeLockVideo);
                    cabinetlockLogService.updateHxpCabinetlockLog(hxpCabinetlockLog);
                }else {
                    logger.error("柜锁关闭修改操作记录失败：" + aioCabinetLockVo.getSubId() + "---------" + result.getLockId());
                }


            }
        }




        result.setSuccess(success);
        result.setMsg(msg);

        return result;

    }


    private CabinetV2Lock doLock(AioCabinetLockVo aioCabinetLockVo, int type){
        CabinetV2Lock result;
        if(LockTypeEnum.SYSTEM.equals(aioCabinetLockVo.getLockType()) && aioCabinetLockVo.getLockId() != null){
            result = hxpCabinetMapper.selectIpAddressByLockId(aioCabinetLockVo.getSubId(), aioCabinetLockVo.getLockId());
        }else {
            result = hxpCabinetMapper.selectByJoinId(aioCabinetLockVo.getJoinId());
            //lockId = hxpCabinetMapper.selectLockIdByJoinId(aioCabinetLockVo.getJoinId());
        }

        try {
            Integer lockId = Integer.parseInt(result.getLockId());
            if(lockId == null){
                logger.error("柜锁参数未设置，执行跳过");
                return result;
            }
            String position = "940";
            if(type == 2){
                position = "2340";
            }
            // 调用开锁接口
            logger.info("执行柜锁调用：" + position + "---------" + lockId);
            CabinetLock cabinetLock = new CabinetLock();
            cabinetLock.setLockId(lockId + "");
            cabinetLock.setPosition(position);
            cabinetLock.setTime("0");
            cabinetLock.setSpeed("0");
            remoteSubQueryService.cabinetLock(cabinetLock);

            // 开始录像
            String ipAddress = result.getIpAddress();
            String closeLockVideo = "";
            boolean success = false;
            if(org.apache.commons.lang3.StringUtils.isNotBlank(ipAddress)){
                if(type == 1){
                    remoteCameraService.startRecord(ipAddress);
                }else {
                    R r = remoteCameraService.stopRecord(ipAddress);
                    if(r != null && HttpStatus.SUCCESS == r.getCode()){
                        closeLockVideo = r.getData() + "";
                        success = true;
                    }else {
                        logger.error("柜锁关闭获取摄像头录像失败：" + r.getMsg());
                    }
                }
            }

            // 添加记录
            if(type == 1){
                HxpCabinetlockLog hxpCabinetlockLog = new HxpCabinetlockLog();
                hxpCabinetlockLog.setCabinetlockId(Long.parseLong(result.getHardwareId()));
                hxpCabinetlockLog.setUnLockTime(DateUtils.getNowDate());
                hxpCabinetlockLog.setOperationType(aioCabinetLockVo.getLockType().getCode());
                hxpCabinetlockLog.setCreateTime(DateUtils.getNowDate());
                hxpCabinetlockLog.setCreateBy(SecurityUtils.getUsername());
                cabinetlockLogService.insertHxpCabinetlockLog(hxpCabinetlockLog);
            }else if(success){
                HxpCabinetlockLog hxpCabinetlockLog = cabinetlockLogMapper.selectByLockId(aioCabinetLockVo.getSubId(), lockId);
                if(hxpCabinetlockLog != null){
                    hxpCabinetlockLog.setCloseLockTime(DateUtils.getNowDate());
                    hxpCabinetlockLog.setCloseLockVideo(closeLockVideo);
                    cabinetlockLogService.updateHxpCabinetlockLog(hxpCabinetlockLog);
                }else {
                    logger.error("柜锁关闭修改操作记录失败：" + aioCabinetLockVo.getSubId() + "---------" + lockId);
                }
            }
        }catch (Exception e){
            logger.error("进行柜锁操作异常（doLock）：" + e.getMessage());
            return result;
        }
        return result;
    }
}
