package com.tykj.dev.device.confirmcheck.utils;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.tykj.dev.device.confirmcheck.common.CheckType;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckBill;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckStat;
import com.tykj.dev.device.confirmcheck.entity.vo.*;
import com.tykj.dev.device.file.service.FilesUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.service.DeviceLibraryCacheService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.packing.service.PackingLibraryService;
import com.tykj.dev.device.task.repository.TaskDao;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.task.subject.bto.TaskBto;
import com.tykj.dev.device.task.subject.domin.Task;
import com.tykj.dev.device.user.base.enums.AuExample;
import com.tykj.dev.device.user.subject.dao.AreaDao;
import com.tykj.dev.device.user.subject.dao.UnitsDao;
import com.tykj.dev.device.user.subject.dao.UserDao;
import com.tykj.dev.device.user.subject.entity.User;
import com.tykj.dev.device.user.subject.entity.bto.AreaUnit;
import com.tykj.dev.device.user.subject.service.AuService;
import com.tykj.dev.misc.base.BeanHelper;
import com.tykj.dev.misc.base.BusinessEnum;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tykj.dev.misc.base.StatusEnum.*;
import static java.util.stream.Collectors.*;

/**
 * ObjTransUtil.
 *
 * @author Matrix <xhyrzldf@gmail.com>
 * @since 2020/8/17 at 8:45 下午
 */
@SuppressWarnings("ALL")
@Slf4j
@Component
public class ObjTransUtil {

    @Autowired
    private UserDao userRepo;

    @Autowired
    private DeviceLibraryDao deviceRepo;

    @Autowired
    private AreaDao areaRepo;

    @Autowired
    private UnitsDao unitRepo;

    @Autowired
    private TaskService taskService;

    @Autowired
    private AuService auService;

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private DeviceLibraryCacheService dlcService;

    @Resource(name = "unMap")
    private Map<String, AreaUnit> unMap;

    @Autowired
    private PackingLibraryService packingLibraryService;


    /**
     * 装备转化为初始化的装备统计类
     *
     * @param device
     * @return
     */
    public CheckDeviceStatVo device2InitStatVo(DeviceLibrary device) {
        String ownUnit = device.getOwnUnit();
        // 这里选择从初始化集合中获取
        String areaName = unMap.get(ownUnit).getName();
        List<CheckAreaStatVo> areaStatList = Lists.newArrayList(new CheckAreaStatVo(areaName, 0, 1, 0, 0, 0, 0));
        return new CheckDeviceStatVo(device.getModel(), device.getName(), 1, areaStatList);
    }

    public CheckDeviceStatVo device2InitStatVo(DeviceLibrary device, String areaName, Integer statId, Integer detailId) {
        List<CheckAreaStatVo> areaStatList = Lists.newArrayList(new CheckAreaStatVo(areaName, 0, 1, 0, 0, statId, detailId));
        return new CheckDeviceStatVo(device.getModel(), device.getName(), 1, areaStatList);
    }

    /**
     * stat 2 table Vo
     *
     * @param stat {@link DeviceCheckStat}
     * @return {@link CheckStatTableVo}
     */
    public CheckStatTableVo stat2TableVo(DeviceCheckStat stat) {

        StringJoiner joiner = new StringJoiner("");

        // 构建姓名参数
        Integer creatorId = stat.getCreateUserId();
        String creatorName = userRepo.findById(creatorId).get().getName();
        List<String> checkUserNames = new ArrayList<>();

        Integer checkUserAId = stat.getCheckUserAId();
        if (checkUserAId != 0) {
            String checkUserAName = userRepo.findById(checkUserAId).get().getName();
            checkUserNames.add(checkUserAName);
            joiner.add(checkUserAName);
        }

        Integer checkUserBId = stat.getCheckUserBId();
        if (checkUserBId != 0) {
            String checkUserBName = userRepo.findById(checkUserBId).get().getName();
            checkUserNames.add(checkUserBName);
            joiner.add(checkUserBName);
        }

        // 构建完成情况参数 未完成数量/总数
        // 获得当前节点的子节点总数 = 总数 其中状态为9999的为已完成
        TaskBto fatherTask = taskService.get(stat.getId(), BusinessEnum.CONFIRM_CHECK_STAT.id);
        Integer fatherTaskId = fatherTask.getId();

        List<Task> childTask = taskDao.findAllByParentTaskId(fatherTaskId);

        boolean flag = false;

        // 3/3 -> 统计待确认 -> 省统计任务待完结
        childTask = childTask.stream()
                .filter(task -> !task.getTitle().contains("统计数据待办任务"))
                .filter(task -> !task.getTitle().contains("统计数据确认任务"))
                .collect(groupingBy(Task::getOwnUnit,
                        collectingAndThen(maxBy(Comparator.comparing(Task::getId)), Optional::get)))
                .values().stream()
                .collect(toList());

        long total = childTask.size();

        long done = childTask.stream()
                .filter(task -> task.getBillStatus().equals(END.id) || task.getBillStatus().equals(CHECK_SHUT_DOWN.id))
                .count();

        //如果是检查统计的话那么还要看一下他的父节点是不是已经完成了
        String completion;
        if (done == total) {
            boolean examFinish = fatherTask.getBillStatus().equals(END.id) || fatherTask.getBillStatus().equals(CHECK_SHUT_DOWN.id);
            if (stat.getCheckType() == CheckType.CT_EXAM && !examFinish) {
                completion = "核查完成待办结";
            } else {
                if (flag) {
                    completion = "核查完成待确认";
                } else {
                    // confirmTaskidDone 为true 代表此时等待最后的father任务 为false代表 flag = false 且isDone为false 代表整个节点里没有确认节点直接完结
                    if (fatherTask.getBillStatus().equals(END.id) || fatherTask.getBillStatus().equals(CHECK_SHUT_DOWN.id)) {
                        completion = "核查完成";
                    } else {
                        completion = "核查完成待办结";
                    }
                }
            }
        } else {
            completion = done + "/" + total;
        }

        joiner.add(stat.getTitle());
        joiner.add(creatorName);
        joiner.add(stat.getCreateTime().toString());
        joiner.add(completion);

        return new CheckStatTableVo(
                stat.getId(),
                stat.getTitle(),
                creatorName,
                checkUserNames,
                stat.getCreateTime(),
                completion,
                stat.getCheckType().getId(),
                joiner.toString(),
                0
        );

    }

    /**
     * Do类转化为Vo类
     */
    public CheckStatVo checkStatDo2Vo(DeviceCheckStat statDo) {
        ModelMapper mapper = MapperHelper.getMapper();
        //复制基本信息
        CheckStatVo initialStat = mapper.map(statDo, CheckStatVo.class);
        // 查询userAName 与 userBName
        User checkUserA = userRepo.findById(statDo.getCheckUserAId()).orElse(null);
        String userAName = checkUserA == null ? "" : checkUserA.getName();
        User checkUserB = userRepo.findById(statDo.getCheckUserBId()).orElse(null);
        String userBName = checkUserB == null ? "" : checkUserB.getName();

        //解析JSON并赋值
        ObjectMapper objectMapper = new ObjectMapper();
        CheckDeviceStatVo[] checkDeviceStatVos = new CheckDeviceStatVo[0];
        try {
            boolean isArray = objectMapper.readTree(statDo.getStatInfo()).isArray();
            if (isArray) {
                checkDeviceStatVos = JacksonUtil.readValue(statDo.getStatInfo(), CheckDeviceStatVo[].class);
            } else {
                CheckDeviceStatVo checkDeviceStatVo = JacksonUtil.readValue(statDo.getStatInfo(), CheckDeviceStatVo.class);
                checkDeviceStatVos = new CheckDeviceStatVo[]{checkDeviceStatVo};
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        initialStat.setDeviceStatVoList(Arrays.asList(checkDeviceStatVos));
        initialStat.setCheckUserAName(userAName);
        initialStat.setCheckUserBName(userBName);
        initialStat.setCheckType(statDo.getCheckType().getId());
        return initialStat;
    }

    public DeviceCheckBill checkBillVo2Do(CheckBillVo vo) {
        ModelMapper modelMapper = BeanHelper.getUserMapper();
        DeviceCheckBill billDo = modelMapper.map(vo, DeviceCheckBill.class);
        billDo.setCheckStatus(0);
        //areas -> unitIds -> unitStrings
        String unitString = vo.getAreaRange().stream()
                .flatMap(id -> unitRepo.findAllByAreaId(id).stream())
                .map(units -> units.getUnitId().toString())
                .collect(Collectors.joining("x"));
        billDo.setCheckDetail(unitString);

        return billDo;
    }

    public DeviceCheckDetail checkDetailVo2Do(CheckDetailVo detailVo) {
        ModelMapper modelMapper = BeanHelper.getUserMapper();
        DeviceCheckDetail detailDo = modelMapper.map(detailVo, DeviceCheckDetail.class);
        //将inLib与notInLib 的集合 转化为压缩字符串
        String checkDetailString = devLib2String(detailVo.getDevInLibrary(), detailVo.getDevNotInLibrary());
        detailDo.setCheckDetail(checkDetailString);

        return detailDo;
    }

    /**
     * 这里不考虑不在库的装备
     *
     * @param inLibrary
     * @param notInLibrary
     * @return
     */
    public String devLib2String(List<DeviceInLibVo> inLibrary, List<DeviceNotInLibVo> notInLibrary) {

        String inLibString = inLibrary.stream()
                .map(lib -> String.format("%d-%d", lib.getId(), lib.getProofResult()))
                .collect(Collectors.joining(","));

        String notInLibString = notInLibrary.stream()
                .map(lib -> String.format("%d-%d", lib.getId(), 3))
                .collect(Collectors.joining(","));

        //不为空则拼接
        String checkDetailString = inLibString;
        if (!CollectionUtils.isEmpty(notInLibrary)) {
            checkDetailString = checkDetailString + "," + notInLibString;
        }
        return checkDetailString;
    }


    public CheckDetailVo CheckDetailDo2Vo(DeviceCheckDetail detailDo) {
        //查询人物id
        Integer checkUserAId = detailDo.getCheckUserAId();
        Integer checkUserBId = detailDo.getCheckUserBId();
        Integer userAId = detailDo.getUserAId();
        Integer userBId = detailDo.getUserBId();

        String checkUserAName = "";
        String checkUserBName = "";
        String userAName = "";
        String userBName = "";

        if (checkUserAId != null && checkUserAId != 0) {
            checkUserAName = userRepo.findById(checkUserAId).orElse(null).getName();
        }

        if (checkUserBId != null && checkUserBId != 0) {
            checkUserBName = userRepo.findById(checkUserBId).orElse(null).getName();
        }

        if (userAId != null && userAId != 0) {
            userAName = userRepo.findById(userAId).orElse(null).getName();
        }

        if (userBId != null && userBId != 0) {
            userBName = userRepo.findById(userBId).orElse(null).getName();
        }

        //解析核查详情 -> 获取id与核查结果
        List<DeviceInLibVo> inLibVoList = new ArrayList<>();
        List<DeviceNotInLibVo> notInLibVoList = new ArrayList<>();
        String checkDetail = detailDo.getCheckDetail();
        List<String> devCheckList = Lists.newArrayList(checkDetail.split(","));
        long start = System.currentTimeMillis();

        Map<Integer, DeviceLibrary> map = dlcService.getAllDeviceLibraryList().stream()
                .collect(toMap(DeviceLibrary::getId, Function.identity()));
        for (String detail : devCheckList) {
            if (StringUtils.isEmpty(detail)) {
                continue;
            }
            String[] array = detail.split("-");
            Integer deviceId = Integer.valueOf(array[0]);
            int proofResult = Integer.parseInt(array[1]);
            // 搜索装备
            DeviceLibrary device = Optional.ofNullable(map.get(deviceId))
                    .orElseThrow(() -> new ApiException(
                            ResponseEntity.badRequest().body(String.format("检查到装备序号为%d的装备不在资料库中，请先执行入库操作!", deviceId)))).setConfigName();

//            DeviceLibrary device = deviceRepo.findById(deviceId).orElseThrow(
//                    () -> new ApiException(ResponseEntity.badRequest().body(String.format("检查到装备序号为%d的装备不在资料库中，请先执行入库操作!", deviceId)))).setConfigName();
            //依据proofResult的个位数 判断是否是在库装备
            int digit = proofResult % 10;
            if (digit == 3) {
                // 非在库装备

                notInLibVoList.add(toCheckNotInLibVo(device));
            } else {
                // 在库装备
                inLibVoList.add(toCheckInLibVo(device, proofResult));
            }
        }
        long end = System.currentTimeMillis();

        log.info("[性能测试] 装备搜索耗时 {} ms", end - start);

        // detailDo -> detailVo
        ModelMapper modelMapper = BeanHelper.getUserMapper();
        CheckDetailVo detailVo = modelMapper.map(detailDo, CheckDetailVo.class);
        detailVo.setCheckUserAName(checkUserAName);
        detailVo.setCheckUserBName(checkUserBName);
        detailVo.setUserAName(userAName);
        detailVo.setUserBName(userBName);
        detailVo.setDevInLibrary(inLibVoList);
        detailVo.setDevNotInLibrary(notInLibVoList);

        String areaName = auService.findOne(AuExample.UnitId, detailDo.getCheckUnitId()).getName();
        detailVo.setCheckArea(areaName);

        detailVo.setRemark(detailDo.getRemark());

        //核查签字单
        if (detailDo.getCheckFiles() != null) {
            detailVo.setCheckFileList(FilesUtil.stringFileToList(detailDo.getCheckFiles()));
        }
        return detailVo;

    }

    public DeviceInLibVo toCheckInLibVo(DeviceLibrary device, int proofResult) {
        return new DeviceInLibVo(
                device.getId(),
                device.getModel(),
                device.getName(),
                device.getSeqNumber(),
                device.getProdNumber(),
                device.getRfidSurfaceId(),
                device.getRfidCardId(),
                proofResult,
                device.getInvisibleRange(),
                device.getType(),
                device.getSecretLevel(),
                device.getInvisibleRangeName(),
                device.getTypeName(),
                device.getSecretLevelName(),
                device.getLifeStatusName(),
                device.getMatchingRangeName(),
                device.getIsPart()
        );
    }

    public DeviceNotInLibVo toCheckNotInLibVo(DeviceLibrary device) {
        return new DeviceNotInLibVo(
                device.getId(),
                device.getModel(),
                device.getName(),
                device.getSeqNumber(),
                device.getProdNumber(),
                device.getRfidSurfaceId(),
                device.getRfidCardId(),
                device.getLocationUnit(),
                device.getOwnUnit(),
                device.getLifeStatus(),
                device.getInvisibleRange(),
                device.getType(),
                device.getSecretLevel(),
                device.getInvisibleRangeName(),
                device.getTypeName(),
                device.getSecretLevelName(),
                device.getLifeStatusName(),
                device.getMatchingRangeName(),
                device.getIsPart()
        );
    }
}

