package com.tykj.dev.device.selfcheck.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.config.base.FileName;
import com.tykj.dev.device.file.entity.FileRet;
import com.tykj.dev.device.file.service.FilesUtil;
import com.tykj.dev.device.selfcheck.repository.SelfCheckBillDao;
import com.tykj.dev.device.selfcheck.service.SelfCheckBillService;
import com.tykj.dev.device.selfcheck.subject.domin.SelfCheckBill;
import com.tykj.dev.device.selfcheck.subject.vo.SelfCheckSelectVo;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.misc.utils.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @author dengdiyi
 */
@Service
public class SelfCheckBillServiceImpl implements SelfCheckBillService {

    @Autowired
    private SelfCheckBillDao selfExaminationBillDao;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    private TaskService taskService;

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

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

    @Override
    public SelfCheckBill update(SelfCheckBill selfExaminationBillEntity) {
        SelfCheckBill selfCheckBill = selfExaminationBillDao.save(selfExaminationBillEntity);
        CompletableFuture.runAsync(()->blockChainUtil.appendHash(JacksonUtil.toJSon(selfCheckBill),selfCheckBill.getRecordId()),TaskBeanConfig.getThreadPoolTaskScheduler());
        return selfCheckBill;
    }

    @Override
    public SelfCheckBill getOne(Integer id) {
        Optional<SelfCheckBill> byId = selfExaminationBillDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("查询的id不存在"));
        } else {
            return byId.get();
        }
    }

    @Override
    public Page<SelfCheckBill> getPage(SelfCheckSelectVo selfCheckSelectVo, Pageable pageable) {
        return selfExaminationBillDao.findAll(getSelectSpecification(selfCheckSelectVo), selfCheckSelectVo.getPageable());
    }

    @Override
    public void delete(Integer id) {
        selfExaminationBillDao.deleteById(id);
    }

    @Override
    public List<SelfCheckBill> findByDate(Date date,String unitName) {
       return selfExaminationBillDao.findAllByCreateTimeAfterAndCheckUnitAndCheckStatusAndCreateUserId(date,unitName,3,null);
    }

    @Override
    public List<SelfCheckBill> findBySystem(String unitName) {
        PredicateBuilder<SelfCheckBill> builder = Specifications.and();
        builder.eq("checkUnit",unitName);
        return selfExaminationBillDao.findAll(builder.build());
    }

    private Specification<SelfCheckBill> getSelectSpecification(SelfCheckSelectVo selfCheckSelectVo) {
        PredicateBuilder<SelfCheckBill> predicateBuilder = Specifications.and();
        predicateBuilder.eq("checkUnit",userUtils.getCurrentUserUnitName());
        if (selfCheckSelectVo != null) {
            if (selfCheckSelectVo.getCheckStatus() != null) {
                predicateBuilder.eq("checkStatus", selfCheckSelectVo.getCheckStatus());
            }
            if (selfCheckSelectVo.getSelfExaminationUnit() != null) {
                predicateBuilder.eq("checkUnit", selfCheckSelectVo.getSelfExaminationUnit());
            }
            if (selfCheckSelectVo.getCheckUserId() != null) {
                predicateBuilder.eq("useraId", selfCheckSelectVo.getCheckUserId());
            }
            if (selfCheckSelectVo.getConfirmUserId() != null) {
                predicateBuilder.eq("userbId", selfCheckSelectVo.getConfirmUserId());
            }
            if (selfCheckSelectVo.getSelfExaminationCycle() != null) {
                predicateBuilder.eq("cycle", selfCheckSelectVo.getSelfExaminationCycle());
            }
            if (selfCheckSelectVo.getCreateUnitId() != null) {
                predicateBuilder.eq("createUnitId", selfCheckSelectVo.getCreateUnitId());
            }
            if (selfCheckSelectVo.getCreateUserId() != null) {
                predicateBuilder.eq("createUserId", selfCheckSelectVo.getCreateUserId());
            }
            if (selfCheckSelectVo.getContent() != null) {
                Class<SelfCheckBill> selfExaminationBillEntityClass = SelfCheckBill.class;
                Field[] declaredFields = selfExaminationBillEntityClass.getDeclaredFields();
                PredicateBuilder<SelfCheckBill> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                        p.like(field.getName(), "%" + selfCheckSelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (selfCheckSelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", selfCheckSelectVo.getStartTime());
            }
            if (selfCheckSelectVo.getEndTime() != null) {
                predicateBuilder.lt("createTime", selfCheckSelectVo.getEndTime());
            }
        }
        return predicateBuilder.build();
    }

    @Override
    public Map<String, List<FileRet>> getFileList(Integer taskId) {
        Map<String, List<FileRet>> map = new HashMap<>();
        Integer billId = taskService.get(taskId).getBillId();
        SelfCheckBill selfCheckBill = getOne(billId);
        //自查单集合
        map.put(FileName.SelfCheck.name, FilesUtil.stringFileToList(selfCheckBill.getCheckFiles()));
        return map;
    }
}
