package com.sptg.device.biz.service.impl;

import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.plugins.pagination.PageHelper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.sptg.common.core.beans.PageBean;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.enums.Instruct;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.device.api.constant.DeviceConstants;
import com.sptg.device.api.dto.*;
import com.sptg.device.api.entity.Device;
import com.sptg.device.api.entity.FlowCard;
import com.sptg.device.api.entity.TimeStrategyPushTask;
import com.sptg.device.api.vo.DeviceVO;
import com.sptg.device.biz.mapper.DeviceMapper;
import com.sptg.device.biz.service.DeviceServiceInterface;
import com.sptg.device.biz.service.FlowCardServiceInterface;
import com.sptg.device.biz.service.MsgPublishService;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;

/**
 * title: DeviceServiceImpl
 * package: com.sptg.device.biz.security.impl
 * description: 设备业务层接口实现
 *
 *
 *
 */
@Service
@AllArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceServiceInterface {

    private final RedisTemplate<String,String> redisTemplate;
    private final FlowCardServiceInterface flowCardServiceInterface;

    /**
     * 设备缓存名称
     */
    private final static String DEVICE_CACHE_NAME = "sptg:device";

    /* ------------------------------------- 重写父类查询方法，过滤已删除的数据 ------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    public List<Device> selectList(Wrapper<Device> wrapper) {
        wrapper.eq("i_status", OperationConstant.ZERO);
        return super.selectList(wrapper);
    }

    @Override
    public Device selectOne(Wrapper<Device> wrapper) {
        wrapper.eq("i_status", OperationConstant.ZERO);
        return super.selectOne(wrapper);
    }

    @Override
    public Page<Device> selectPage(Page<Device> page) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        return this.selectPage(page,wrapper);
    }

    @Override
    public Page<Device> selectPage(Page<Device> page, Wrapper<Device> wrapper) {
        wrapper.eq("i_status", OperationConstant.ZERO);
        return super.selectPage(page, wrapper);
    }

    /* -------------------------------------- 重写父类修改方法，删除Redis缓存 --------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean updateById(Device entity) {
        boolean result = super.updateById(entity);
        if (result){
            this.redisTemplate.opsForHash().delete(DEVICE_CACHE_NAME, entity.getId().toString());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean updateBatchById(List<Device> entityList) {
        boolean result = super.updateBatchById(entityList);
        if (result){
            HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
            entityList.forEach(item -> hashOperations.delete(DEVICE_CACHE_NAME, item.getId().toString()));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean update(Device entity, Wrapper<Device> wrapper) {
        boolean result = super.update(entity, wrapper);
        if (result){
            //  删除缓存
            List<Device> entityList = this.selectList(wrapper);
            if (entityList.size() > 0){
                HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
                entityList.forEach(item -> hashOperations.delete(DEVICE_CACHE_NAME, item.getId().toString()));
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean deleteBatchIds(Collection<? extends Serializable> idList) {
        boolean result = super.deleteBatchIds(idList);
        if (result){
            HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
            idList.forEach(item -> hashOperations.delete(DEVICE_CACHE_NAME, item.toString()));
        }
        return result;
    }

    /* -------------------------------------------------- 业务代码 -------------------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    public Device selectById(Serializable id) {
        //  查询缓存
        HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
        String hashKey = id.toString();
        String json = hashOperations.get(DEVICE_CACHE_NAME, hashKey);
        if (StringUtils.isEmpty(json)){
            //  查询数据库
            Wrapper<Device> wrapper = new EntityWrapper<>();
            wrapper.eq("l_id",id);
            Device device = this.selectOne(wrapper);
            if (null != device){
                json = JsonUtils.objectToJson(device);
                hashOperations.put(DEVICE_CACHE_NAME,hashKey,json);
            }
            return device;
        }
        return JsonUtils.jsonToPojo(json,Device.class);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean insert(Device entity) {
        entity.setCreateDate(new Date());
        entity.setStatus(OperationConstant.ZERO);
        return super.insert(entity);
    }

    @Override
    public Page<Device> pagingQuery(PageBean<Device,DeviceDto> pageBean) {
        DeviceDto dto = pageBean.getDto();
        //  排序字段 时间降序
        pageBean.setOrderByField("t_create_date").setAsc(false);
        //  构建查询条件
        Wrapper<Device> wrapper = new EntityWrapper<>();
        if (!StringUtils.isEmpty(dto.getVersion())){
            String sql = "i_version_number is null";
            wrapper.notIn("i_version_number",dto.getVersion()).or(sql);
        }
        if (!StringUtils.isEmpty(dto.getSmallVersion())){
            wrapper.ge("i_version_number",dto.getSmallVersion());
        }
        if (!StringUtils.isEmpty(dto.getBigVersion())){
            wrapper.lt("i_version_number",dto.getBigVersion());
        }
        if (!StringUtils.isEmpty(dto.getXqName())){
            wrapper.like("s_xq_name",dto.getXqName(),SqlLike.DEFAULT);
        }
        if (!StringUtils.isEmpty(dto.getName())){
            wrapper.like("s_name",dto.getName(),SqlLike.DEFAULT);
        }
        if (!StringUtils.isEmpty(dto.getSerialNumber())){
            wrapper.like("s_serial_number",dto.getSerialNumber(),SqlLike.DEFAULT);
        }
        if (!StringUtils.isEmpty(dto.getVersionNumber())){
            wrapper.eq("i_version_number",dto.getVersionNumber());
        }
        if(!StringUtils.isEmpty(dto.getRegionProvince())){
            wrapper.eq("s_region_province",dto.getRegionProvince());
        }
        if (!StringUtils.isEmpty(dto.getRegionCity())){
            wrapper.eq("s_region_city",dto.getRegionCity());
        }
        if (!StringUtils.isEmpty(dto.getRegionArea())){
            wrapper.eq("s_region_area",dto.getRegionArea());
        }
        if (!StringUtils.isEmpty(dto.getDeviceFactory())){
            wrapper.eq("s_device_factory",dto.getDeviceFactory());
        }
        if (!StringUtils.isEmpty(dto.getDeviceModelNumber())){
            wrapper.eq("s_type_code",dto.getDeviceModelNumber());
        }
        if (null != dto.getXqId()){
            wrapper.eq("l_xq_id",dto.getXqId());
        }
        if (dto.getUnitId() != null){
            wrapper.eq("l_unit_id",dto.getUnitId());
        }
        if (StringUtils.isEmpty(dto.getSearchText())) {
            if (!StringUtils.isEmpty(dto.getName())) {
                wrapper.like("s_name", dto.getName(), SqlLike.DEFAULT);
            }
            if (!StringUtils.isEmpty(dto.getSerialNumber())) {
                wrapper.like("s_serial_number", dto.getSerialNumber(), SqlLike.RIGHT);
            }
        }else {
            String sql = "(s_name like concat('%',{0},'%') or s_serial_number like concat('%',{0},'%'))";
            wrapper.and(sql,dto.getSearchText());
        }
//          查询在线或离线的设备（下面判断筛选）
        if (null != dto.getOnlineStatus()) {
            long nowTime = System.currentTimeMillis();
            if (0 == dto.getOnlineStatus()) {
                //  离线
                String sql = "( i_last_heartbeat IS NULL OR i_last_heartbeat < {0} )";
                wrapper.and(sql,nowTime - HEART_RATE);
            } else {
                //  在线
                wrapper.gt("i_last_heartbeat",nowTime - HEART_RATE);
            }
        }

        if (!StringUtils.isEmpty(dto.getOrgPosition())){
            wrapper.like("s_org_position",dto.getOrgPosition(),SqlLike.RIGHT);
        }
        if (!StringUtils.isEmpty(dto.getEstatePosition())){
            wrapper.like("s_estate_position", dto.getEstatePosition(), SqlLike.RIGHT);
        }

        //排序
        if (dto.getSortField() != null && dto.getSortOrder() != null){
            wrapper.orderBy(dto.getSortField(),dto.getSortOrder().equals("asc"));
        }

        wrapper.like("s_org_position",dto.getOrgPosition(),SqlLike.RIGHT);
        //是否是流量卡绑定页面
        if (dto.getIsFlowCardDevice()){
            wrapper.isNull("l_flow_card_id");
        }
        //  查询设备列表,设置在线状态，30分钟为换一次心跳频率，最后通讯时间如果在30分钟内，则表示在线，否则离线
        Page<Device> page = this.selectPage(pageBean, wrapper);
        List<Device> records = new ArrayList<Device>();
//        long overTime = System.currentTimeMillis() - 1000 * 60 * 30;
        //  查询设备列表,设置在线状态，3分钟为换一次心跳频率，最后通讯时间如果在30分钟内，则表示在线，否则离线
        long overTime = System.currentTimeMillis() - 1000 * 60 * 3;
        page.getRecords().forEach(device -> {
            if (device.getFlowCardId() != null){
                FlowCard flowCard = this.flowCardServiceInterface.selectById(device.getFlowCardId());
                if (flowCard != null){
                    device.setFlowCard(flowCard);
                }
            }
            device.setOnlineStatus(0);
            if (null != device.getLastHeartbeat()){
                if (device.getLastHeartbeat() > overTime){
                    device.setOnlineStatus(1);
                }
            }
            if(device.getDeviceFactory().equals(DeviceConstants.DEVICE_FACTORY_QINLIN)){
                device.setOnlineStatus(OperationConstant.ONE);
            }
//              查询在线或离线的设备
            if (dto.getOnlineStatus() != null){
                if (dto.getOnlineStatus().equals(device.getOnlineStatus())){
                    records.add(device);
                }
            }else{
                records.add(device);
            }
        });
        page.setRecords(records);
        return page;
    }

    @Override
    public List<Device> selectListByXqId(Long xqId) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("l_xq_id",xqId);
        return this.selectList(wrapper);
    }

    @Override
    public List<Device> selectListByDyId(Long dyId) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("l_unit_id",dyId);
        return this.selectList(wrapper);
    }

    @Override
    public Page<Device> selectListByRegion(Long regionId, Page<Device> page) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        String sql = "(s_region_province = {0} or s_region_city = {0} or s_region_area = {0})";
        wrapper.and(sql,regionId);
        return this.selectPage(page,wrapper);
    }

    @Override
    public Device selectBySerialNumber(String serialNumber) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("s_serial_number",serialNumber);
        wrapper.eq("i_status",OperationConstant.ZERO);
        return this.selectOne(wrapper);
    }

    @Override
    public Device selectByFactory(String factory) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("s_device_factory",factory);
        wrapper.eq("i_status",OperationConstant.ZERO);
        return this.selectOne(wrapper);
    }

    @Override
    public Integer selectMaxXqSort(Long xqId) {
        Integer max = this.baseMapper.selectMaxXqSort(xqId);
        return null == max ? OperationConstant.ONE : max + 1;
    }

    @Override
    public List<Device> getListByEstateUser(Long xqId, Long unitId) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("l_xq_id",xqId);
        if (null != unitId) {
            String sql = "( l_unit_id is null or l_unit_id in ({0}))";
            wrapper.and(sql,unitId);
        }
        return this.selectList(wrapper);
    }

    /**
     * 获取住户可访问的指定厂商设备列表
     * @return List<Device>
     */
    @Override
    public List<Device> getListByCondition(DeviceVO deviceVO) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("l_xq_id",deviceVO.getXqId());
        Long unitId = deviceVO.getUnitId();
        if (null != unitId) {
            String sql = "( l_unit_id is null or l_unit_id in ({0}))";
            wrapper.and(sql, unitId);
        }
        String factory = deviceVO.getFactory();
        if(factory != null){
            Integer inOrNotIn = deviceVO.getInOrNotIn();
            if(inOrNotIn != null){
                if(inOrNotIn.equals(OperationConstant.ONE)){
                    wrapper.in("s_device_factory", factory);
                }else{
                    wrapper.notIn("s_device_factory", factory);
                }
            }
        }
        return this.selectList(wrapper);
    }

    @Override
    public List<Device> getListByOrgPosition(DeviceVO deviceVO) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.like("s_org_position", deviceVO.getFactory(), SqlLike.RIGHT);
        wrapper.eq("i_status",OperationConstant.ZERO);
        return this.selectList(wrapper);
    }

    /**
     *
     * @param xqId 小区Id
     * @param unitId 单元Id
     * @param pathUse 设备位置的用途
     * @return
     */
    @Override
    public List<Device> getListByPathUse(Long xqId, Long unitId, Integer pathUse) {
        List<Device> devices = baseMapper.selectListByPathUse(xqId, unitId, pathUse);
        return devices;
    }

    @Override
    public List<Device> getOfflineDeviceAccount(Device device) {
        return baseMapper.getOfflineDeviceAccount(device.getOrgPosition());
    }

    /**
     *
     * @param xqId
     * @param unitId
     * @param pathUse
     * @param type 1：卡片机，2：人脸机，3：卡片人脸机
     * @return
     */
    @Override
    public List<Device> getDeviceByPathUseAndType(Long xqId, Long unitId, Integer pathUse, Integer type) {
        if(type != null){
            switch (type){
                case 1:
                    return baseMapper.selectCardListByPathUse(xqId, unitId, pathUse);
                case 2:
                    return baseMapper.selectFaceListByPathUse(xqId, unitId, pathUse);
                case 3:
                    return baseMapper.selectFaceCardListByPathUse(xqId, unitId, pathUse);
                default:
                    return baseMapper.selectListByPathUse(xqId, unitId, pathUse);
            }
        }else{
            return baseMapper.selectListByPathUse(xqId, unitId, pathUse);
        }
    }

    @Override
    public ResultBean<Page<Device>> pagingByResidentialIds(DeviceDto deviceDto) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("i_status",OperationConstant.ZERO);
        wrapper.in("l_xq_id",deviceDto.getResidentialIds());
        if (deviceDto.getIdList() != null && deviceDto.getIdList().size() > 0){
            wrapper.notIn("l_id",deviceDto.getIdList());
        }
        return new ResultBean<>(ResultEnum.SUCCESS,this.selectPage(deviceDto.getPage(),wrapper));
    }
    @Override
    public boolean complete(DeviceDto deviceDto) {
        boolean result = this.updateAllColumnById(deviceDto);
        if(result){
            HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
            Long id = deviceDto.getId();
            String hashKey = id.toString();
            Wrapper<Device> wrapper = new EntityWrapper<>();
            wrapper.eq("l_id", id);
            Device device = this.selectOne(wrapper);
            if (null != device){
                String json = JsonUtils.objectToJson(device);
                hashOperations.put(DEVICE_CACHE_NAME,hashKey,json);
            }
        }
        return result;
    }

    @Override
    public Page<Device> getPageByCondition(PageBean<Device, DeviceDto> pageBean) {
        DeviceDto dto = pageBean.getDto();
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.eq("i_status", OperationConstant.ZERO);
        if(StringUtils.hasText(dto.getDeviceFactory())){
            wrapper.eq("s_device_factory", dto.getDeviceFactory());
        }
        Page<Device> devicePage = this.selectPage(pageBean, wrapper);
        return devicePage;
    }

    @Override
    public List<Device> getListBySerialNumbers(String serialNumbers) {
        Wrapper<Device> wrapper = new EntityWrapper<>();
        wrapper.in("s_serial_number",serialNumbers.split(","));
        wrapper.eq("i_status",OperationConstant.ZERO);
        return this.selectList(wrapper);
    }

}
