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.config.base.FileName;
import com.tykj.dev.device.file.entity.FileRet;
import com.tykj.dev.device.file.service.FilesUtil;
import com.tykj.dev.device.repair.repository.RepairSendBillDao;
import com.tykj.dev.device.repair.service.RepairSendBillService;
import com.tykj.dev.device.repair.subject.domin.RepairSendBill;
import com.tykj.dev.device.repair.subject.vo.RepairBillSelectVo;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.user.subject.service.UserPublicService;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * @author dengdiyi
 */
@Service
public class RepairSendBillServiceImpl implements RepairSendBillService {

    @Autowired
    private UserPublicService userService;

    @Autowired
    private RepairSendBillDao deviceRepairSendBillDao;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    private TaskService taskService;

    @Override
    public RepairSendBill addEntity(RepairSendBill deviceRepairSendBillEntity) {
        RepairSendBill repairSendBill = deviceRepairSendBillDao.save(deviceRepairSendBillEntity);
        CompletableFuture.runAsync(()->{
            RepairSendBill repairSendBill1 = getOne(repairSendBill.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(repairSendBill1));
            String recordId = bcText.getData().getRecordID();
            repairSendBill1.setRecordId(recordId);
            deviceRepairSendBillDao.save(repairSendBill1);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
        return repairSendBill;
    }

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

    @Override
    public Page<RepairSendBill> getPage(RepairBillSelectVo deviceRepairBillSelectVo, Pageable pageable) {
        Page<RepairSendBill> page = deviceRepairSendBillDao.findAll(getSelectSpecification(deviceRepairBillSelectVo), deviceRepairBillSelectVo.getPageable());
        for (RepairSendBill d : page.getContent()) {
            d.setStartUserA(userService.getOne(d.getStartUseraId()).getName());
            d.setStartUserB(userService.getOne(d.getStartUserbId()).getName());
            d.setRepairUserA(userService.getOne(d.getRepairUseraId()).getName());
            d.setRepairUserB(userService.getOne(d.getRepairUserbId()).getName());
        }
        return page;
    }

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

    @Override
    public RepairSendBill update(RepairSendBill deviceRepairSendBillEntity) {
        RepairSendBill repairSendBill = deviceRepairSendBillDao.save(deviceRepairSendBillEntity);
        CompletableFuture.runAsync(()->blockChainUtil.appendHash(JacksonUtil.toJSon(repairSendBill),deviceRepairSendBillEntity.getRecordId()),TaskBeanConfig.getThreadPoolTaskScheduler());
        return repairSendBill;
    }

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

    @Override
    public Map<String, List<FileRet>> getFileList(Integer taskId) {
        Map<String, List<FileRet>> map = new HashMap<>();
        Integer billId = taskService.get(taskId).getBillId();
        RepairSendBill repairSendBill = getOne(billId);
        //收件方签收单集合
        map.put(FileName.SIGN.name, FilesUtil.stringFileToList(repairSendBill.getReceiveFiles()));
        //发件方回执单集合
        map.put(FileName.RECEIPT.name,FilesUtil.stringFileToList(repairSendBill.getSendFiles()));
        return map;
    }

    @Override
    public RepairSendBill findByRepairdId(Integer repairId) {
        return deviceRepairSendBillDao.findByDeviceRepairBillId(repairId);
    }


    private Specification<RepairSendBill> getSelectSpecification(RepairBillSelectVo deviceRepairBillSelectVo) {
        PredicateBuilder<RepairSendBill> predicateBuilder = Specifications.and();
        if (deviceRepairBillSelectVo != null) {
            if (deviceRepairBillSelectVo.getRepairUseraId() != null) {
                predicateBuilder.eq("repairUseraId", deviceRepairBillSelectVo.getRepairUseraId());
            }
            if (deviceRepairBillSelectVo.getReceiveUnit() != null) {
                predicateBuilder.eq("receiveUnit", deviceRepairBillSelectVo.getReceiveUnit());
            }
            if (deviceRepairBillSelectVo.getRepairUserbId() != null) {
                predicateBuilder.eq("repairUserbId", deviceRepairBillSelectVo.getRepairUserbId());
            }
            if (deviceRepairBillSelectVo.getStartUseraId() != null) {
                predicateBuilder.eq("startUseraId", deviceRepairBillSelectVo.getStartUseraId());
            }
            if (deviceRepairBillSelectVo.getStartUserbId() != null) {
                predicateBuilder.eq("startUserbId", deviceRepairBillSelectVo.getStartUserbId());
            }
            if (deviceRepairBillSelectVo.getContent() != null) {
                Class<RepairSendBill> deviceRepairBillEntityClass = RepairSendBill.class;
                Field[] declaredFields = deviceRepairBillEntityClass.getDeclaredFields();
                PredicateBuilder<RepairSendBill> 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("updateTime", deviceRepairBillSelectVo.getEndTime());
            }
        }
        return predicateBuilder.build();
    }
}
