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

import com.github.wenhao.jpa.Specifications;
import com.tykj.dev.device.finalcheck.entity.domain.FinalDetail;
import com.tykj.dev.device.finalcheck.entity.domain.FinalReport;
import com.tykj.dev.device.finalcheck.entity.vo.FinalRemakeVo;
import com.tykj.dev.device.finalcheck.entity.vo.FinalReportSelectVo;
import com.tykj.dev.device.finalcheck.entity.vo.FinalReportVo;
import com.tykj.dev.device.finalcheck.repisotry.FinalDetailDao;
import com.tykj.dev.device.finalcheck.repisotry.FinalReportDao;
import com.tykj.dev.device.finalcheck.service.FinalCheckService;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.device.usereport.service.DeviceUseReportService;
import com.tykj.dev.device.usereport.subject.vo.DeviceStatistics;
import com.tykj.dev.misc.exception.ApiException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tykj.dev.misc.utils.TimestampUtil.localDateToDate;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toMap;

/**
 * FinalCheckServiceImpl.
 *
 * @author Matrix <xhyrzldf@gmail.com>
 * @since 2020/9/28 at 2:26 下午
 */
@Service
public class FinalCheckServiceImpl implements FinalCheckService {

    @Autowired
    private FinalReportDao reportDao;

    @Autowired
    private FinalDetailDao detailDao;

    @Autowired
    private DeviceLibraryDao deviceDao;

    @Autowired
    private DeviceUseReportService dataService;

    @Autowired
    private UserUtils userService;

//    @Autowired
//    private ScrapBillDao scrapBillDao;
//
//    @Autowired
//    private DeviceDestroyBillDao deviceDestroyBillDao;
//
//    @Autowired
//    private UnitsDao unitsDao;
//
//    @Autowired
//    private RepairSendBillDao repairSendBillDao;
//
//    @Autowired
//    private RepairBackBillDao repairBackBillDao;
//
//    @Autowired
//    private AllotBillDao allotBillDao;
//
//    @Autowired
//    private DeviceLibraryService deviceLibraryService;

    @Override
    public FinalReportVo generateReport(LocalDate startTime, LocalDate endTime) {
        String name = startTime+"～"+endTime + "决算报告";
        String unitName = userService.getCurrentUserUnitName();
        String operatorName = userService.getCurrentName();
        FinalReport report = new FinalReport(name, unitName, startTime, endTime, LocalDateTime.now(), operatorName);
        report = reportDao.save(report);
        // 查询这段时间内该单位下的所有装备 并且计数
        long l = System.currentTimeMillis();
//        List<DeviceLibrary> devices = deviceDao.findAllByUnitBetweenTime(unitName, localDateToDate(startTime), localDateToDate(endTime));
        List<DeviceLibrary> devices = deviceDao.findAll();
        System.out.println(System.currentTimeMillis()-l);
//
//        PredicateBuilder<DeviceLibrary> builder = Specifications.and();
//        builder.eq("ownUnit",unitName);
//        List<DeviceLibrary> devices = deviceDao.findAll(builder.build());
        // 纵向-查 横向-0 委托-0 合计-合计 代管0 收到 发出 报废0
        Map<String, List<DeviceLibrary>> map = devices.stream()
                .collect(groupingBy(deviceLibrary -> deviceLibrary.getModel()+"Ǵ"+deviceLibrary.getName()));
        //报废
//        List<ScrapBill> scrapBills = scrapBillDao.findAllByUnitBetweenTime(unitName, localDateToDate(startTime), localDateToDate(endTime));

        //根据单位名称查询单位id
//        Units units = unitsDao.findByName(unitName);
//        Integer unitId = units.getUnitId();
        //销毁
//        List<DeviceDestroyBill> destroyBills = deviceDestroyBillDao.findAllByUnitBetweenTime(unitId, localDateToDate(startTime), localDateToDate(endTime));
//
//        //维修送修
//        List<RepairSendBill> repairSendBills = repairSendBillDao.findAllByUnitBetweenTime(unitName, localDateToDate(startTime), localDateToDate(endTime));
//
//        //送修退回
//        List<RepairBackBill> repairBackBills = repairBackBillDao.findAllByUnitBetweenTime(unitName, localDateToDate(startTime), localDateToDate(endTime));

        List<FinalDetail> detailList = new ArrayList<>();
        //入库
        Map<String, DeviceStatistics> storageMap = dataService.getStorageStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));
        //送修
        Map<String, DeviceStatistics> repairMap = dataService.getRepairStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));

        //维修退回
        Map<String, DeviceStatistics> repairBackMap = dataService.getRepairBackStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));
        //销毁
        Map<String, DeviceStatistics> destroyMap = dataService.getDestroyStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));
        //报废
        Map<String, DeviceStatistics> scrapMap = dataService.getScrapStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));

        //退役
        Map<String, DeviceStatistics> retireMap = dataService.getDecommissioningStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel()+"Ǵ"+deviceStatistics.getName(), Function.identity()));
        //丢失
        Map<String, DeviceStatistics> lossMap = dataService.getLossStatistics(localDateToDate(startTime), localDateToDate(endTime))
                .stream()
                .collect(toMap(deviceStatistics -> deviceStatistics.getModel() + "G" + deviceStatistics.getName(), Function.identity()));
        for (Map.Entry<String, List<DeviceLibrary>> entry : map.entrySet()) {
            String key = entry.getKey();
            List<DeviceLibrary> v = entry.getValue();
            //纵向
            List<DeviceLibrary> vList = v.stream().filter(deviceLibrary -> deviceLibrary.getMatchingRange() == 1 ).collect(Collectors.toList());
            //横向
            List<DeviceLibrary> hList = v.stream().filter(deviceLibrary -> deviceLibrary.getMatchingRange() == 2 || deviceLibrary.getMatchingRange() == 3).collect(Collectors.toList());
            //其他
            List<DeviceLibrary> otherList = v.stream().filter(deviceLibrary -> deviceLibrary.getMatchingRange() == 4).collect(Collectors.toList());

            //收到的  入库+维修退回（中办送回）
            //发出的  送修
            Integer storage = storageMap.get(key) == null ? 0 : storageMap.get(key).getNum();
            Integer repairBack = repairBackMap.get(key) == null ? 0 : repairBackMap.get(key).getNum();
            Integer sending = repairMap.get(key) == null ? 0 : repairMap.get(key).getNum();
            Integer retire = retireMap.get(key) == null ? 0 : retireMap.get(key).getNum();
            Integer scrap = scrapMap.get(key) == null ? 0 : scrapMap.get(key).getNum();
            Integer destroy = destroyMap.get(key) == null ? 0 : destroyMap.get(key).getNum();
            Integer loss = lossMap.get(key) == null ? 0 : destroyMap.get(key).getNum();
//            detailList.add(new FinalDetail(v.get(0).getModel(), v.get(0).getName(), v.size(), 0, 0, 0, v.size(),
//                    0, received, sending, 0, report.getId()));
            detailList.add(new FinalDetail(v.get(0).getModel(), v.get(0).getName(), vList.size(), hList.size(), 0, otherList.size(), v.size(),
                    0, storage+repairBack, sending, scrap,report.getId(),loss ,"",destroy));
        }

        detailList = detailDao.saveAll(detailList);

        return report.toVo(detailList);
    }


    @Override
    public Page<FinalReportVo> findAllWithoutDetail(FinalReportSelectVo finalReportSelectVo) {
        LocalDate startTime = finalReportSelectVo.getStartTime();
        LocalDate endTime = finalReportSelectVo.getEndTime();
        String keyword = finalReportSelectVo.getKeyword();
        boolean timeQuery = Objects.nonNull(startTime) && Objects.nonNull(endTime);
        // 如果没有携带关键字且没有指定时间查询，则直接查询，否则添加时间条件
        if (StringUtils.isEmpty(finalReportSelectVo.getKeyword())) {
            if (timeQuery) {
                Specification<FinalReport> pred = Specifications.<FinalReport>and()
                        .gt("startTime", startTime)
                        .lt("endTime", endTime)
                        .build();

                return reportDao.findAll(pred, finalReportSelectVo.getPageable())
                        .map(report -> report.toVo(Collections.emptyList()));
            } else {
                return reportDao.findAll(finalReportSelectVo.getPageable())
                        .map(report -> report.toVo(Collections.emptyList()));
            }
        } else {
            // 如果携带关键字，则构造条件查询器
            Specification<FinalReport> pred = Specifications.<FinalReport>or()
                    .like("name", "%" + keyword + "%")
                    .like("operator", "%" + keyword + "%")
                    .predicate(timeQuery, Specifications.and()
                            .gt("startTime", startTime)
                            .lt("endTime", endTime)
                            .build()
                    )
                    .build();

            return reportDao.findAll(pred, finalReportSelectVo.getPageable())
                    .map(report -> report.toVo(Collections.emptyList()));
        }

    }

    @Override
    public FinalReportVo findReportById(Integer id) {
        FinalReport report = reportDao.findById(id)
                .orElseThrow(() -> new ApiException("查询的id不存在!"));

        List<FinalDetail> detailList = detailDao.findByReportId(report.getId())
                .orElse(Collections.emptyList());
        //按照名称排序
        List<FinalDetail> finalDetails = detailList.stream().sorted(Comparator.comparing(FinalDetail::getModel)).collect(Collectors.toList());
        return report.toVo(finalDetails);
    }

    @Override
    public FinalDetail addRemake(FinalRemakeVo finalRemakeVo) {
        //查询
        FinalDetail finalDetail = null;
        Optional<FinalDetail> byId = detailDao.findById(finalRemakeVo.getId());
        if (byId.isPresent()){
            finalDetail = byId.get();
            finalDetail.setRemake(finalRemakeVo.getRemake());
        }
        //更新
        FinalDetail save = detailDao.save(finalDetail);
        return save;
    }
}
