package com.yx.face.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yx.face.boot.core.BaseController;
import com.yx.face.boot.restful.RestDTO;
import com.yx.face.boot.restful.RestResponse;
import com.yx.face.boot.restful.RestResult;
import com.yx.face.boot.restful.ServiceException;
import com.yx.face.boot.uitls.BeanUtils;
import com.yx.face.boot.uitls.DateUtils;
import com.yx.face.boot.uitls.JsonUtils;
import com.yx.face.boot.uitls.SMSOrIdCardUtils;
import com.yx.face.dao.*;
import com.yx.face.model.dto.UserWhitelistDTO;
import com.yx.face.model.entity.*;
import com.yx.face.model.excel.UserWhitelistExcel;
import com.yx.face.model.search.UserWhitelistSearch;
import com.yx.face.model.vo.AdminVO;
import com.yx.face.model.vo.UserWhitelistVO;
import com.yx.face.service.*;
import com.yx.face.service.feign.TBDeviceFaceService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @ClassName UserWhitelistServiceImpl
 * @Author WXG
 * @Date 2021/11/5 14:16
 */
@Slf4j
@Service
public class UserWhitelistServiceImpl implements UserWhitelistService {

    @Autowired
    private UserInfoService userInfoService;

    @Resource
    private UserWhitelistDao userWhitelistdao;

    @Resource
    private UserBlackListService userBlackListService;

    @Resource
    private AdminService adminService;

    @Resource
    private FaceDeviceDao faceDeviceDao;

    @Resource
    private FaceRequestLogDao faceRequestLogDao;

    @Autowired
    private TBDeviceFaceService tbDeviceFaceService;

    @Resource
    private FacePassDao facePassDao;

    @Resource
    private FaceTaskDao faceTaskDao;

    @Resource
    private UserVisitorListDao userVisitorListDao;

    @Autowired
    private AsyncTriggerRetryImpl asyncTriggerRetryImpl;
    @Autowired
    private SystemLongTermDocumentsService systemLongTermDocumentsService;

    @Override
    public Integer insert(UserWhitelistDTO userWhitelistDTO) {
        //参数校验
        UserWhitelist userWhitelist = getUserWhitelist(userWhitelistDTO);
        //新增前先判断访客列表有没有数据，如果有，就拿过来，填充到常客列表，否则不填充
        UserVisitorList userVisitorListByPhone = userVisitorListDao.selectByPhoneAndAdminId(userWhitelistDTO.getPhone(), userWhitelistDTO.getAdminId());
        if (null != userVisitorListByPhone) {
            userWhitelist.setAvatar(userVisitorListByPhone.getAvatar());
            //userWhitelist.setIdNumber(userVisitorListByPhone.getIdNumber());
            userWhitelist.setStatus(1);//访客列表有信息，说明已经认证
            //访客有数据就把访客列表中数据删除
            userVisitorListDao.deleteByPrimaryKey(userVisitorListByPhone.getId());
        }

        userWhitelist.setCreateTime(new Date());
        userWhitelist.setUpdateTime(new Date());
        userWhitelist.setType(1);
        if (null == userWhitelist.getStatus()) {
            userWhitelist.setStatus(2);
        }
        return userWhitelistdao.insert(userWhitelist);
    }

    @Override
    public Integer update(UserWhitelistDTO userWhitelistDTO) {
        if (userWhitelistDTO.getId() == null) {
            throw new ServiceException("修改时常客主键不能为空");
        }
        UserWhitelist userWhitelist = getUserWhitelist(userWhitelistDTO);
        userWhitelist.setId(userWhitelistDTO.getId());
        userWhitelist.setUpdateTime(new Date());
        return userWhitelistdao.updateByPrimaryKeySelective(userWhitelist);
    }

    //数据校验
    private UserWhitelist getUserWhitelist(UserWhitelistDTO userWhitelistDTO) {
        UserWhitelist userWhitelist = new UserWhitelist();

        //姓名校验
        if (null == userWhitelistDTO.getName() || userWhitelistDTO.getName().equals("")) {
            throw new ServiceException("姓名有误");
        }

        //校验手机号
        if (userWhitelistDTO.getPhone() == null || userWhitelistDTO.getPhone().equals("")) {
            throw new ServiceException("手机号不能为空");
        }
        if (!SMSOrIdCardUtils.isMobile(userWhitelistDTO.getPhone())) {
            throw new ServiceException("手机号有误");
        }
        UserWhitelist userWhitelistDb = userWhitelistdao.selectByPhone(userWhitelistDTO.getPhone());
        if (userWhitelistDb != null) {
            throw new ServiceException("手机号已经存在");
        }

        //检验身份证号
        if (null == userWhitelistDTO.getIdNumber() || userWhitelistDTO.getIdNumber().equals("") ) {
            throw new ServiceException("身份证号不能为空");
        }
        if (!SMSOrIdCardUtils.isIdCard(userWhitelistDTO.getIdNumber())) {
            throw new ServiceException("身份证号有误");
        }
        userWhitelistDb = userWhitelistdao.selectByIdNumber(userWhitelistDTO.getIdNumber());
        if (null != userWhitelistDb && null != userWhitelistDb.getId()) {
            throw new ServiceException("身份证号已经存在");
        }

        //校验分配账号
        if (null == userWhitelistDTO.getAdminId() || null == adminService.showDataGetInfo(userWhitelistDTO.getAdminId())) {
            throw new ServiceException("所分配账号有误");
        }
        //与人员管理进行比较,判断是否存在
        Boolean flag = systemLongTermDocumentsService.getByIdNumber(userWhitelistDTO.getIdNumber());
        if (flag){
            throw new ServiceException("身份证号已经在人员名单中存在");
        }
        userWhitelist.setAdminId(userWhitelistDTO.getAdminId());
        userWhitelist.setName(userWhitelistDTO.getName());
        userWhitelist.setPhone(userWhitelistDTO.getPhone());
        userWhitelist.setIdNumber(userWhitelistDTO.getIdNumber());
        return userWhitelist;
    }


    @Override
    public Integer delete(Integer id, Integer adminId) {
//        return userWhitelistdao.deleteByPrimaryKey(id);
//        List<String> msg = new ArrayList<>();
        UserWhitelist userWhitelist = userWhitelistdao.selectByPrimaryKey(id);
        //判断白名单是否存在
        if (userWhitelist == null) {
            throw new ServiceException("该数据已不存在，请刷新页面再试哦~");
        }
//        List<String> faceDeviceNo = faceDeviceDao.selectListNo(userWhitelist.getAdminId());
//        if (!faceDeviceNo.isEmpty()) {
//            for (String s : faceDeviceNo) {
//                msg.add(s + ":设备离线或未授权或未启用");
//            }
//        }
        //获取 adminId所有设备
        //List<String> faceDeviceOne = faceDeviceDao.selectList(userWhitelist.getAdminId());
        //List<FaceDevice> snList = faceDeviceDao.getByAdminAndType(userWhitelist.getAdminId());
        //List<String> faceDeviceOne = snList.stream().map(FaceDevice::getSn).collect(Collectors.toList());
        //查询超管旗下所有设备
        AdminVO info = adminService.getInfo();
        List<String> faceDeviceOne = faceDeviceDao.getByAminVo(info);

        if (faceDeviceOne.isEmpty()) {
            throw new ServiceException("该设备不存在或离线，请刷新页面再试哦~");
        }
        Long userId = userWhitelistdao.setUserOne(id, userWhitelist.getAdminId());
        //获取设备 删除人脸
        for (String sn : faceDeviceOne) {
            Map<String, Object> result;
            // 1. entrySet遍历，在键和值都需要时使用（最常用）
            Map<String, Object> params = com.beust.jcommander.internal.Maps.newHashMap();
            Date now = new Date();
            List<Map<String, Object>> data = new ArrayList<>();
            Map<String, Object> userMap = com.beust.jcommander.internal.Maps.newHashMap();
            userMap.put("pin", userId);
            data.add(userMap);
            List<Long> userIds = new ArrayList<>();
            userIds.add(userId);
            params.put("Data", data);
            params.put("SN", sn);
            FaceRequestLog requestLog = new FaceRequestLog();
            requestLog.setName("删除人员人脸信息");
            requestLog.setContext("/delUser");
            requestLog.setParams(JsonUtils.toJson(params));
            requestLog.setStatus(0);
            requestLog.setUsedTime(0L);
            requestLog.setUpdateTime(now);
            requestLog.setCreateTime(now);
            faceRequestLogDao.insertSelective(requestLog);
            params.put("taskId", requestLog.getId());
            try {
                result = tbDeviceFaceService.delUser(params);
                if (!StringUtils.equals("命令下发成功", (String) result.get("msg"))) {
                    //异步下发三次
                    asyncTriggerRetryImpl.delUserRetry(params);
                } else {
                    faceTaskDao.updateFaceTaskStatus(sn, userIds);
                }
                log.info("删除结果={}", result);
            } catch (Exception e) {
                asyncTriggerRetryImpl.delUserRetry(params);
                log.info("删除人脸异常 {}", e.getMessage());
            }
        }
        userWhitelistdao.deleteByPrimaryKey(id);
        return 1;
    }

    @Override
    public PageInfo<UserWhitelistVO> getPageList(RestDTO<UserWhitelistSearch> dto) {
        UserWhitelistSearch data = dto.getData();

        if (data.getPhone() != null && !data.getPhone().equals("") && (!SMSOrIdCardUtils.isMobile(data.getPhone()))) {
            throw new ServiceException("手机号查询时须填写完整");
        }
        AdminVO info = adminService.getInfo();
        Map<String, Object> map = new HashMap<>();
        map.put("adminVo", info);
        map.put("uws", dto.getData());

        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<UserWhitelistVO> list = userWhitelistdao.selectListBySearch(map);
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getPhone() != null)
                list.get(i).setPhone(SMSOrIdCardUtils.hidePhone(list.get(i).getPhone()));
            if (list.get(i).getIdNumber() != null)
                list.get(i).setIdNumber(SMSOrIdCardUtils.hideIdNumber(list.get(i).getIdNumber()));
            if (list.get(i).getName() != null)
                list.get(i).setName(SMSOrIdCardUtils.hideName(list.get(i).getName().trim()));
        }
        return new PageInfo<>(list);
    }

    @Override
    public RestResult<List<String>> uploadUserWhitelistExcel(List<Object> datas,Integer userId) {

        List<String> list = new ArrayList<>();
        for (int i = 0; i < datas.size(); i++) {
            try {
                UserWhitelistExcel userWhitelistExcel = (UserWhitelistExcel) datas.get(i);
                if (userWhitelistExcel.getName() == null) throw new ServiceException("第" + (i + 2) + "行,姓名不能为空");
                if (userWhitelistExcel.getPhone() == null) throw new ServiceException("第" + (i + 2) + "行,手机号不能为空");
                if (userWhitelistExcel.getIdNumber() == null) throw new ServiceException("第" + (i + 2) + "行,身份证不能为空");

                UserWhitelistDTO userWhitelistDTO = new UserWhitelistDTO();
                userWhitelistDTO.setName(userWhitelistExcel.getName());
                userWhitelistDTO.setPhone(userWhitelistExcel.getPhone());
                userWhitelistDTO.setIdNumber(userWhitelistExcel.getIdNumber());
                userWhitelistDTO.setAdminId(userId);
                try {
                    this.insert(userWhitelistDTO);
                } catch (Exception e) {
                    throw new ServiceException("第" + (i + 2) + "行," + e.getMessage());
                }
            } catch (ServiceException e) {
                list.add(e.getMessage());
                continue;
            }
        }
        datas.clear();//结束后销毁不用的资源
        return RestResponse.ok(list);
    }

    /**
     * @param deviceId
     * @return
     */
    @Override
    public RestResult<String> addSnIssued(Integer deviceId) {
        List<String> msg = new ArrayList<>();
        RestResult<String> objectRestResult = new RestResult<>();
        //获取 adminId所有设备
        FaceDevice faceDevice = new FaceDevice();
        faceDevice.setId(deviceId);
        faceDevice.setOnline(1);
        faceDevice.setEnable(1);
        faceDevice.setAuth(1);
        FaceDevice faceDeviceOne = faceDeviceDao.selectOne(faceDevice);
        if (faceDeviceOne == null) {
            objectRestResult.setCode(401);
            objectRestResult.setMsg("设备不在线或设备未授权");
            return objectRestResult;
        }
        //人脸下发
        Date now = new Date();
        Date date = DateUtils.addYears(now, 1);
        //获取 adminId 下的常客
        List<UserWhitelistVO> list = userWhitelistdao.selectList(faceDeviceOne.getAdminId());
        for (UserWhitelistVO userWhitelist : list) {
            //判断是否有照片
            if (StringUtils.isBlank(userWhitelist.getAvatar())) {
                //记录错误信息
                msg.add(userWhitelist.getName() + ":下发失败人脸照片不规范");
                continue;
            } else {
                userWhitelist.setSn(faceDeviceOne.getSn());
                userWhitelist.setAdminId(faceDeviceOne.getAdminId());
                try {
                    String avatar = userInfoService.getAvatarBase64(userWhitelist.getId(), userWhitelist.getAvatar());
                    if (StringUtils.isBlank(avatar)) {
                        msg.add(userWhitelist.getName() + ":人脸照片不规范请重试哦");
                    } else {
                        userWhitelist.setAvatar(avatar);
                    }
                    downFaceByTask(userWhitelist, DateUtils.addMinutes(now, -10), date, 2);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        if (msg.isEmpty()) {
            objectRestResult.setCode(200);
            objectRestResult.setMsg("下发成功");
        } else {
            objectRestResult.setCode(200);
            objectRestResult.setMsg(msg.toString());
        }
        return objectRestResult;
    }

    @Override
    public RestResult<String> addSingle(Integer userId, Integer id) {
        RestResult<String> objectRestResult = new RestResult<>();
        UserWhitelistVO one = userWhitelistdao.selectListOne(id);
        //获取base64 图片
        String avatar = userInfoService.getAvatarBase64(one.getId(), one.getAvatar());
        if (StringUtils.isBlank(avatar)) {
            throw new ServiceException("人脸照片不规范请重试哦");
        } else {
            one.setAvatar(avatar);
        }
        //查询超管旗下所有设备
        AdminVO info = adminService.getInfo();
        //List<String> faceDeviceOne = faceDeviceDao.selectList(one.getAdminId());
        List<String> faceDeviceOne = faceDeviceDao.getByAminVo(info);
        if (faceDeviceOne.isEmpty()) {
            //objectRestResult.setCode(401);
            //objectRestResult.setMsg("设备不在线常客名单全量失败");
            throw new ServiceException("设备不在线常客名单全量失败");
            //return objectRestResult;
        }
        //人脸下发
        Date now = new Date();
        Date date = DateUtils.addYears(now, 1);
        one.setAdminId(userId);
        for (String s : faceDeviceOne) {
            one.setSn(s);
            try {
                downFaceByTask(one, DateUtils.addMinutes(now, -10), date, 2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        objectRestResult.setCode(200);
        objectRestResult.setMsg("下发成功");
        return objectRestResult;
    }


    /**
     * @param whitelistVO 对应数据
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @param type        类型
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> downFaceByTask(UserWhitelistVO whitelistVO, Date startTime, Date endTime, Integer type) throws Exception {
        Map<String, Object> result = new HashMap<>();
        //天波人脸服务请求日志表
        FaceRequestLog requestLog;
        Date now = new Date();
        //人脸下发表
        FacePass facePass;
        //唯一id
        Long faceTaskId;
        //人脸清除定时任务
        FaceTask faceTask;
        //信息
        String msg;
        //人脸下发到设备里面
        Map<String, Object> params = Maps.newHashMapWithExpectedSize(3);
        List<Map<String, Object>> data = Lists.newArrayListWithExpectedSize(1);
        Map<String, Object> dataItem = Maps.newHashMapWithExpectedSize(8);
        FaceDevice faceDeviceBySn = faceDeviceDao.getFaceDeviceBySn(whitelistVO.getSn());
        // 下发参数
        dataItem.put("pin", whitelistVO.getId());
        dataItem.put("name", whitelistVO.getName());
        dataItem.put("validPeriodStart", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime));
        dataItem.put("validPeriodEnd", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime));
        dataItem.put("userType", 0);
        dataItem.put("photo", whitelistVO.getAvatar());
        dataItem.put("rightno", 105);
        dataItem.put("cardid", whitelistVO.getIdNumber());
        data.add(dataItem);
        params.put("SN", whitelistVO.getSn());
        params.put("Data", data);
        //天波人脸服务请求日志表
        requestLog = new FaceRequestLog();
        requestLog.setName("下发人脸");
        requestLog.setContext("/downUser");
        requestLog.setParams("");
        requestLog.setStatus(1);
        requestLog.setUsedTime(0L);
        requestLog.setUpdateTime(now);
        requestLog.setCreateTime(now);
        //人脸下发记录表
        faceRequestLogDao.insertSelective(requestLog);
        params.put("taskId", requestLog.getId());
        //人脸下发表
        facePass = new FacePass();
        facePass.setUserId(whitelistVO.getId());
        facePass.setDeviceSn(faceDeviceBySn.getSn());
        facePass.setDeviceId(faceDeviceBySn.getId());
        facePass.setStartTime(startTime);
        facePass.setEndTime(endTime);
        facePass.setAdminId(whitelistVO.getAdminId());
        facePass.setStatus(2);
        facePass.setType(type);
        facePass.setTaskId(whitelistVO.getAdminId().toString());
        facePass.setUpdateTime(now);
        facePass.setCreateTime(now);
        //人脸下发
        facePassDao.insertSelective(facePass);
        asyncTriggerRetryImpl.send(params, facePass);
        faceTaskId = faceTaskDao.getFaceTaskId(whitelistVO.getSn(), whitelistVO.getId());
        faceTask = new FaceTask();
        faceTask.setId(faceTaskId);
        faceTask.setTaskTime(facePass.getEndTime());
        faceTask.setStatus(0);
        faceTask.setUpdateTime(now);
        if (faceTaskId == null) {
            faceTask.setDeviceSn(whitelistVO.getSn());
            faceTask.setUserId(whitelistVO.getId());
            faceTask.setCreateTime(now);
            faceTaskDao.insertSelective(faceTask);
        }
        faceTaskDao.updateByPrimaryKeySelective(faceTask);
        return result;
    }
}
