package com.tykj.dev.device.scrap.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
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.subject.vo.ScriptSaveVo;
import com.tykj.dev.device.scrap.repository.ScrapBillDao;
import com.tykj.dev.device.scrap.service.ScrapBillService;
import com.tykj.dev.device.scrap.subject.domin.ScrapBill;
import com.tykj.dev.device.scrap.subject.vo.ScrapSelectVo;
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

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

/**
 * @author dengdiyi
 */
@Service
public class ScrapBillServiceImpl implements ScrapBillService {

    @Autowired
    private ScrapBillDao scrapBillDao;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Override
    public ScrapBill add(ScrapBill scrapBill) {
        ScrapBill scrapBill1 = scrapBillDao.save(scrapBill);
        CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ScrapBill scrapBill2 = getOne(scrapBill1.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(scrapBill2));
            String recordId = bcText.getData().getRecordID();
            scrapBill2.setRecordId(recordId);
            scrapBillDao.save(scrapBill2);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
        return scrapBill1;
    }

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

    @Override
    public ScrapBill getOne(Integer id) {
        Optional<ScrapBill> scrapBillOptional = scrapBillDao.findById(id);
        if (scrapBillOptional.isPresent()) {
            ScrapBill scrapBill=scrapBillOptional.get();
            scrapBill.setScripts(JacksonUtil.readValue(scrapBill.getScriptJson(), new TypeReference<List<ScriptSaveVo>>() {
            }));
            return scrapBill;
        } else {
            throw new ApiException(ResultUtil.failed("查询Id不存在"));
        }
    }

    @Override
    public ScrapBill update(ScrapBill scrapBill) {
        ScrapBill scrapBill1 = scrapBillDao.save(scrapBill);
        CompletableFuture.runAsync(()->blockChainUtil.appendHash(JacksonUtil.toJSon(scrapBill1),scrapBill1.getRecordId()),TaskBeanConfig.getThreadPoolTaskScheduler());
        return scrapBill1;
    }

    @Override
    public Page<ScrapBill> getPage(ScrapSelectVo scrapSelectVo) {
        PredicateBuilder<ScrapBill> predicateBuilder = Specifications.and();
        if (scrapSelectVo.getContent() != null) {
            Class<ScrapBill> scrapBillClass = ScrapBill.class;
            Field[] declaredFields = scrapBillClass.getDeclaredFields();
            PredicateBuilder<ScrapBill> p = Specifications.or();
            for (Field field : declaredFields) {
                if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                    p.like(field.getName(), "%" + scrapSelectVo.getContent() + "%");
                }
            }
            predicateBuilder.predicate(p.build());
        }
        if (scrapSelectVo.getStartTime() != null) {
            predicateBuilder.gt("scrapTime", scrapSelectVo.getStartTime());
        }
        if (scrapSelectVo.getEndTime() != null) {
            predicateBuilder.lt("scrapTime", scrapSelectVo.getEndTime());
        }
        return scrapBillDao.findAll(predicateBuilder.build(), scrapSelectVo.getPageable());
    }
}
