package com.tykj.dev.device.destroy.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.service.BlockChainUtil;
import com.tykj.dev.config.base.DeviceLifeStatus;
import com.tykj.dev.device.destroy.entity.domain.DeviceDestroyBill;
import com.tykj.dev.device.destroy.entity.vo.DestroySelectVo;
import com.tykj.dev.device.destroy.repository.DeviceDestroyBillDao;
import com.tykj.dev.device.destroy.service.DeviceDestroyBillService;
import com.tykj.dev.device.file.entity.FileRet;
import com.tykj.dev.device.file.service.FilesUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.library.subject.vo.ScriptSaveVo;
import com.tykj.dev.device.user.subject.service.UnitsService;
import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.misc.base.BusinessEnum;
import com.tykj.dev.misc.base.StatusEnum;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.DeviceSeqUtil;
import com.tykj.dev.misc.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;


/**
 * @author zjm
 */
@Service
@Slf4j
public class DeviceDestroyBillServiceImpl implements DeviceDestroyBillService {

    @Autowired
    private DeviceDestroyBillDao deviceDestroyBillDao;

    @Autowired
    private UserPublicService userService;

    @Autowired
    UnitsService unitsService;

    @Autowired
    private DeviceLibraryService deviceLibraryService;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    DeviceLibraryDao deviceLibraryDao;


    @Override
    public DeviceDestroyBill saveDeviceDestroyBill(DeviceDestroyBill scrap) {
        CompletableFuture.runAsync(()-> {
        if (scrap.getRecordId() == null || scrap.getRecordId().equals("")) {
            scrap.setRecordId(blockChainUtil.sendText(1000, JacksonUtil.toJSon(scrap)).getData().getRecordID());
            deviceDestroyBillDao.save(scrap);
            log.info("[销毁]上链数据时间本次");
        } else {
            scrap.setRecordId(blockChainUtil.appendText(JacksonUtil.toJSon(scrap), scrap.getRecordId()).getData().getRecordID());
            deviceDestroyBillDao.save(scrap);
        }
    });
        return deviceDestroyBillDao.save(scrap);
    }

    @Override
    public DeviceDestroyBill findDeviceDestroyBill(Integer scrapId) {
        Optional<DeviceDestroyBill> optional = deviceDestroyBillDao.findById(scrapId);
        if (optional.isPresent()){
            DeviceDestroyBill deviceDestroyBill=optional.get();
            deviceDestroyBill.setScripts(JacksonUtil.readValue(deviceDestroyBill.getScriptJson(), new TypeReference<List<ScriptSaveVo>>() {}));
            deviceDestroyBill.setApplyFileList(FilesUtil.stringFileToList(deviceDestroyBill.getApplyFiles()));
            deviceDestroyBill.setDestructionFileList(FilesUtil.stringFileToList(deviceDestroyBill.getDestructionFiles()));
            deviceDestroyBill.setReplayFileList(FilesUtil.stringFileToList(deviceDestroyBill.getReplayFiles()));
            deviceDestroyBill.setUnitName(unitsService.findById(deviceDestroyBill.getUnitId()).getName());
            List<String> seqNumbers=new ArrayList<>();
            JacksonUtil.readValue(deviceDestroyBill.getScriptJson(), new TypeReference<List<ScriptSaveVo>>() {}).forEach(
                    scriptSaveVo -> {
                        if (scriptSaveVo.getSeqNumber()!=null){
                            seqNumbers.addAll(DeviceSeqUtil.selectDeviceSeqs(scriptSaveVo.getSeqNumber()));
                        }
                    }
            );
            deviceDestroyBill.setDeviceLibraryEntities(deviceLibraryDao.findAllBySeqNumberIn(seqNumbers).stream().map(DeviceLibrary::setConfigName).collect(Collectors.toList()));
            return deviceDestroyBill;
        }else {
            log.info("[销毁] 详情查看错误，id没有找到{}",scrapId);
            throw new ApiException(ResponseEntity.status(500).body("报废详情id没有找到:"+scrapId));
        }
    }

    @Override
    public List<DeviceDestroyBill> findAll() {
        return deviceDestroyBillDao.findAll();
    }

    @Override
    public Optional<DeviceDestroyBill> findApplyId(Integer applyId) {
        return deviceDestroyBillDao.findByApplyId(applyId);
    }

    @Override
    public Page<DeviceDestroyBill> findPageDeviceDestroyBill(DestroySelectVo destroySelectVo) {
        return deviceDestroyBillDao.findAll(getFindRetiredSpecification(destroySelectVo),destroySelectVo.getPageable()).map(
                deviceDestroyBill -> {
                    deviceDestroyBill.setScripts(JacksonUtil.readValue(deviceDestroyBill.getScriptJson(), new TypeReference<List<ScriptSaveVo>>() {}));
                    deviceDestroyBill.setApplyFileList(FilesUtil.stringFileToList(deviceDestroyBill.getApplyFiles()));
                    deviceDestroyBill.setDestructionFileList(FilesUtil.stringFileToList(deviceDestroyBill.getDestructionFiles()));
                    deviceDestroyBill.setReplayFileList(FilesUtil.stringFileToList(deviceDestroyBill.getReplayFiles()));
                    deviceDestroyBill.setUnitName(unitsService.findById(deviceDestroyBill.getUnitId()).getName());
                    return deviceDestroyBill;
        });
    }

    private Specification<DeviceDestroyBill> getFindRetiredSpecification(DestroySelectVo destroySelectVo) {
        PredicateBuilder<DeviceDestroyBill> predicateBuilder = Specifications.and();
        if (destroySelectVo.getStartTime() != null) {
            predicateBuilder.gt("createTime", destroySelectVo.getStartTime());
        }
        if (destroySelectVo.getEndTime() != null) {
            predicateBuilder.lt("createTime", destroySelectVo.getEndTime());
        }
        predicateBuilder.eq("destroyStatus", StatusEnum.END.id);
        return predicateBuilder.build();

    }
}
