package com.tykj.dev.device.repair.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.repair.repository.RepairBillDao;
import com.tykj.dev.device.repair.service.RepairBillService;
import com.tykj.dev.device.repair.subject.domin.RepairBill;
import com.tykj.dev.device.repair.subject.vo.RepairBillSelectVo;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.utils.JacksonUtil;
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.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * @author dengdiyi
 */
@Service
public class RepairBillServiceImpl implements RepairBillService {

    @Autowired
    private RepairBillDao deviceRepairBillDao;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private BlockChainUtil blockChainUtil;

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

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

    @Override
    public Page<RepairBill> getPage(RepairBillSelectVo deviceRepairBillSelectVo, Pageable pageable) {
        return deviceRepairBillDao.findAll(getSelectSpecification(deviceRepairBillSelectVo), pageable);
    }

    @Override
    public RepairBill getOne(Integer id) {
        Optional<RepairBill> resultEntity = deviceRepairBillDao.findById(id);
        return resultEntity.orElse(null);
    }

    @Override
    public RepairBill update(RepairBill deviceRepairBillEntity) {
        RepairBill repairBill = deviceRepairBillDao.save(deviceRepairBillEntity);
        CompletableFuture.runAsync(()-> blockChainUtil.appendHash(JacksonUtil.toJSon(repairBill),repairBill.getRecordId()), TaskBeanConfig.getThreadPoolTaskScheduler());
        return repairBill;
    }

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

    private Specification<RepairBill> getSelectSpecification(RepairBillSelectVo deviceRepairBillSelectVo) {
        PredicateBuilder<RepairBill> predicateBuilder = Specifications.and();
        PredicateBuilder<RepairBill> predicateBuilder1 = Specifications.or();
        predicateBuilder1.eq("sendUnit", userUtils.getCurrentUserUnitName());
        predicateBuilder1.eq("receiveUnit", userUtils.getCurrentUserUnitName());
        predicateBuilder.predicate(predicateBuilder1.build());
        if (deviceRepairBillSelectVo != null) {
            if (deviceRepairBillSelectVo.getReceiveUnit() != null) {
                predicateBuilder.eq("receiveUnit", deviceRepairBillSelectVo.getReceiveUnit());
            }
            if (deviceRepairBillSelectVo.getSendUnit() != null) {
                predicateBuilder.eq("sendUnit", deviceRepairBillSelectVo.getSendUnit());
            }
            if (deviceRepairBillSelectVo.getContent() != null) {
                Class<RepairBill> deviceRepairBillEntityClass = RepairBill.class;
                Field[] declaredFields = deviceRepairBillEntityClass.getDeclaredFields();
                PredicateBuilder<RepairBill> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                        p.like(field.getName(), "%" + deviceRepairBillSelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (deviceRepairBillSelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", deviceRepairBillSelectVo.getStartTime());
            }
            if (deviceRepairBillSelectVo.getEndTime() != null) {
                predicateBuilder.lt("createTime", deviceRepairBillSelectVo.getEndTime());
            }
        }
        predicateBuilder.notIn("repairStatus", 0);
        return predicateBuilder.build();
    }
}
