package com.tykj.dev.rfid.service.impl;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.tykj.dev.blockcha.subject.entity.BcHash;
import com.tykj.dev.blockcha.subject.service.BlockChainUtil;
import com.tykj.dev.config.TaskBeanConfig;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.rfid.entity.domin.LibraryWarningLog;
import com.tykj.dev.rfid.entity.domin.LibraryWarningLogDetail;
import com.tykj.dev.rfid.entity.vo.LibraryWarningLogSelectVo;
import com.tykj.dev.rfid.entity.vo.WarningCountVo;
import com.tykj.dev.rfid.entity.vo.WarningDetailListVo;
import com.tykj.dev.rfid.entity.vo.WarningHandleVo;
import com.tykj.dev.rfid.repository.LibraryWarningLogDao;
import com.tykj.dev.rfid.repository.LibraryWarningLogDetailDao;
import com.tykj.dev.rfid.service.LibraryWarningLogService;
import com.tykj.dev.rfid.utils.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author dengdiyi
 */
@Service
public class LibraryWarningLogServiceImpl implements LibraryWarningLogService {

    @Resource
    UserUtils userUtils;
    @Resource
    DeviceLibraryService deviceLibraryService;
    @Autowired
    LibraryWarningLogDetailDao libraryWarningLogDetailDao;
    @Autowired
    private LibraryWarningLogDao libraryWarningLogDao;
    @Autowired
    private BlockChainUtil blockChainUtil;

    @Override
    public LibraryWarningLog addEntity(LibraryWarningLog libraryWarningLog) {
        LibraryWarningLog libraryWarningLog1 = libraryWarningLogDao.save(libraryWarningLog);
        CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LibraryWarningLog libraryWarningLog2 = getOne(libraryWarningLog1.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(libraryWarningLog2));
            String recordId = bcText.getData().getRecordID();
            libraryWarningLog2.setRecordId(recordId);
            libraryWarningLogDao.save(libraryWarningLog2);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
        return libraryWarningLog1;
    }

    /**
     * @param libraryWarningLogs 异步上链
     */
    @Override
    @Async
    public void sendHash(List<LibraryWarningLog> libraryWarningLogs) {
        libraryWarningLogs.forEach(libraryWarningLog1 -> {
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(libraryWarningLog1));
            String recordId = bcText.getData().getRecordID();
            libraryWarningLog1.setRecordId(recordId);
            update(libraryWarningLog1);
        });
    }

    @Override
    public Page<LibraryWarningLog> getPage(LibraryWarningLogSelectVo libraryWarningLogSelectVo) throws ParseException {
        Specification<LibraryWarningLog> selectSpecification = getSelectSpecification(libraryWarningLogSelectVo);
        return libraryWarningLogDao.findAll(selectSpecification, libraryWarningLogSelectVo.getPageable());
    }


    @Override
    public List<WarningDetailListVo> getWarningDetail(Integer warningId, Boolean isHandle) {
        List<WarningDetailListVo> warningDetailVos = new ArrayList<>();
        PredicateBuilder<LibraryWarningLogDetail> and = Specifications.and();
        and.eq("libraryWarningLogId", warningId);
        if (isHandle != null && isHandle) {
            and.eq("warningHandle", 1);
        }
        List<LibraryWarningLogDetail> all = libraryWarningLogDetailDao.findAll(and.build());
        all.stream().forEach(d -> {
            WarningDetailListVo detailVo = new WarningDetailListVo();
            if (d.getDeviceId() != null) {
                DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(d.getDeviceId());
                BeanUtils.copyProperties(d, detailVo);
                detailVo.setDeviceLibraryEntity(deviceLibraryEntity);
            } else {
                DeviceLibrary deviceLibraryEntity = new DeviceLibrary();
                deviceLibraryEntity.setName("未知装备");
                deviceLibraryEntity.setModel("未知型号");
                deviceLibraryEntity.setRfidCardId("");
                deviceLibraryEntity.setRfidSurfaceId("");
                deviceLibraryEntity.setType(0);
                BeanUtils.copyProperties(d, detailVo);
                detailVo.setDeviceLibraryEntity(deviceLibraryEntity);
            }
            warningDetailVos.add(detailVo);
        });
        return warningDetailVos;
    }

    @Override
    public Integer updateDetailHandleResult(WarningHandleVo warningHandleVo) {
        LibraryWarningLogDetail detailEntity = libraryWarningLogDetailDao.findById(warningHandleVo.getWarningDetailId()).get();
        detailEntity.setHandleResult(warningHandleVo.getHandleResult());
        detailEntity.setWarningHandle(1);
        LibraryWarningLogDetail save = libraryWarningLogDetailDao.save(detailEntity);
        return save.getLibraryWarningLogId();
    }

    @Override
    public LibraryWarningLog getOne(Integer id) {
        return libraryWarningLogDao.findById(id).get();
    }

    @Override
    public WarningCountVo getCount(LibraryWarningLogSelectVo libraryWarningLogSelectVo) throws ParseException {

        //获取时间段告警数量
        Long localWarning = libraryWarningLogDao.count(getSelectSpecification(libraryWarningLogSelectVo));
        //获取盘点告警数量
        libraryWarningLogSelectVo.setWarningType(Arrays.asList(2));
        Long inventoryWarning = libraryWarningLogDao.count(getSelectSpecification(libraryWarningLogSelectVo));
        //获取出入库告警数量
        libraryWarningLogSelectVo.setWarningType(Arrays.asList(0, 1));
        Long enterOutWarning = libraryWarningLogDao.count(getSelectSpecification(libraryWarningLogSelectVo));
        //获取未处理告警数量
        libraryWarningLogSelectVo.setWarningType(null);
        libraryWarningLogSelectVo.setWarningHandle(0);
        Long handleWaring = libraryWarningLogDao.count(getSelectSpecification(libraryWarningLogSelectVo));
        return new WarningCountVo(localWarning, inventoryWarning, enterOutWarning, handleWaring);
    }

    @Override
    public LibraryWarningLog update(LibraryWarningLog libraryWarningLog) {
        LibraryWarningLog libraryWarningLog1 = libraryWarningLogDao.save(libraryWarningLog);
        CompletableFuture.runAsync(()->blockChainUtil.appendHash(JacksonUtil.toJSon(libraryWarningLog1),libraryWarningLog1.getRecordId()),TaskBeanConfig.getThreadPoolTaskScheduler());
        return libraryWarningLog1;
    }

    private Specification<LibraryWarningLog> getSelectSpecification(LibraryWarningLogSelectVo libraryWarningLogSelectVo) throws ParseException {
        PredicateBuilder<LibraryWarningLog> predicateBuilder = Specifications.and();
        if (libraryWarningLogSelectVo.getUnit() != null) {
            predicateBuilder.eq("unit", libraryWarningLogSelectVo.getUnit());
        } else {
            predicateBuilder.eq("unit", userUtils.getCurrentUserUnitName());
        }

        if (libraryWarningLogSelectVo.getInventoryResults() != null) {
            predicateBuilder.like("inventoryResults", "%" + libraryWarningLogSelectVo.getInventoryResults() + "%");
        }

        if (libraryWarningLogSelectVo.getStatus() != null) {
            predicateBuilder.eq("status", libraryWarningLogSelectVo.getStatus());
        }

        if (libraryWarningLogSelectVo.getWarningType() != null) {
            predicateBuilder.in("warningType", libraryWarningLogSelectVo.getWarningType().toArray());
        }
        if (libraryWarningLogSelectVo.getContent() != null) {
            Class<LibraryWarningLog> libraryWarningLogEntityClass = LibraryWarningLog.class;
            Field[] declaredFields = libraryWarningLogEntityClass.getDeclaredFields();
            PredicateBuilder<LibraryWarningLog> p = Specifications.or();
            for (Field field : declaredFields) {
                if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                    p.like(field.getName(), "%" + libraryWarningLogSelectVo.getContent() + "%");
                }
            }
            predicateBuilder.predicate(p.build());
        }

        if (libraryWarningLogSelectVo.getTime() != null) {
            switch (libraryWarningLogSelectVo.getTime()) {
                case 0:
                    //设置查询条件为本年
                    predicateBuilder.ge("createTime", DateUtils.getYearStart());
                    predicateBuilder.le("createTime", DateUtils.getYearEnd());
                    break;
                case 1:
                    //设置查询条件为本月
                    predicateBuilder.ge("createTime", DateUtils.getMonthStart());
                    predicateBuilder.le("createTime", DateUtils.getMonthEnd());
                    break;
                case 2:
                    //设置查询条件为本周
                    predicateBuilder.ge("createTime", DateUtils.getWeekStart());
                    predicateBuilder.le("createTime", DateUtils.getWeekEnd());
                    break;
                case 3:
                    //设置查询条件为本日
                    predicateBuilder.like("createTime", "%" + DateUtils.getToday() + "%");
                    break;
                default:
                    break;
            }
            ;
        }

        if (libraryWarningLogSelectVo.getStartTime() != null) {
            predicateBuilder.ge("createTime", libraryWarningLogSelectVo.getStartTime());
        }
        if (libraryWarningLogSelectVo.getEndTime() != null) {
            predicateBuilder.le("createTime", libraryWarningLogSelectVo.getEndTime());
        }
        return predicateBuilder.build();
    }
}
