package com.tykj.dev.statistical.service.impl;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
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.repair.repository.RepairDetailDao;
import com.tykj.dev.device.repair.repository.RepairSendBillDao;
import com.tykj.dev.device.repair.service.RepairBillService;
import com.tykj.dev.device.repair.subject.domin.RepairDetail;
import com.tykj.dev.device.repair.subject.domin.RepairSendBill;
import com.tykj.dev.device.selfcheck.repository.SelfCheckBillDao;
import com.tykj.dev.device.selfcheck.subject.domin.SelfCheckBill;
import com.tykj.dev.device.task.repository.TaskDao;
import com.tykj.dev.device.task.subject.domin.Task;
import com.tykj.dev.device.user.cache.UnitsCache;
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.Area;
import com.tykj.dev.device.user.subject.entity.Units;
import com.tykj.dev.device.user.subject.entity.User;
import com.tykj.dev.misc.base.BusinessEnum;
import com.tykj.dev.misc.utils.StringSplitUtil;
import com.tykj.dev.statistical.cache.StatisticalCache;
import com.tykj.dev.statistical.service.BigScreenService;
import com.tykj.dev.statistical.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dengdiyi
 */
@Service
@Slf4j
public class BigScreenServiceImpl implements BigScreenService {

    @Autowired
    private StatisticalCache statisticalCache;

    @Autowired
    private DeviceLibraryDao deviceLibraryDao;

    @Autowired
    private AreaDao areaDao;

    @Autowired
    private UnitsCache unitsCache;

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private UnitsDao unitsDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private RepairSendBillDao repairSendBillDao;

    @Autowired
    private RepairBillService repairBillService;

    @Autowired
    private RepairDetailDao repairDetailDao;

    @Autowired
    private SelfCheckBillDao selfCheckBillDao;

    @Autowired
    private DeviceLibraryService deviceLibraryService;

    /**
     * 获取省及各市装备统计信息
     */
    @Override
    public List<DevNum> getAllDeviceNum() {
        List<DevNum> devNumList = new ArrayList<>();
        List<DevNum> devNums = new ArrayList<>(statisticalCache.getDevNums());
        //获取所有装备
        List<DeviceLibrary> deviceLibraries = deviceLibraryDao.findAll();
        //获取省本级
        List<Area> areas = areaDao.findAreasByType(1);
        //获取所有单位
        List<Units> units = unitsCache.findAll();
        //统计各市装备数量
        for (Area area:areas) {
            DevNum devNum = new DevNum();
            devNum.setAreaName(area.getName());
            //根据区域id找单位id集合
            List<String> names = units.stream()
                    .filter(units1 -> area.getId().equals(units1.getAreaId()))
                    .map(Units::getName)
                    .collect(Collectors.toList());
            //筛选出所属单位在id集合中的装备
            List<DeviceLibrary> deviceLibraryList = deviceLibraries.stream()
                    .filter(deviceLibrary -> names.contains(deviceLibrary.getOwnUnit()))
                    .collect(Collectors.toList());
            //获取装备总数量
            devNum.setCount(deviceLibraryList.size());
            devNumList.add(devNum);
        }
        devNumList.addAll(devNums);
        return devNumList;
    }

    /**
     * 获取全省某业务每月数量统计
     *
     * @param businessType
     */
    @Override
    public List<BusinessNum> getBusinessNum(Integer businessType) {
        List<BusinessNum> businessNums = new ArrayList<>();
        for (int i =1;i<13;i++){
            BusinessNum businessNum = new BusinessNum();
            businessNum.setMonth(i);
            businessNums.add(businessNum);
        }
        List<Task> tasks = taskDao.findAllByBusinessType(businessType);
        tasks.forEach(task -> {
            if (isPresentYear(task.getCreateTime())) {
                int month = getMonth(task.getCreateTime());
                BusinessNum businessNum = businessNums.get(month - 1);
                businessNum.setCount(businessNum.getCount() + 1);
            }
        });
        return businessNums;
    }

    /**
     * 获取大屏中心信息统计
     */
    @Override
    public CenterNum getCenterNum() {
        CenterNum centerNum = new CenterNum();
        //装备总数
        centerNum.setDeviceCount(deviceLibraryService.getDeviceCount());
        //本年度业务总数
        centerNum.setBusinessCount((int) taskDao.findAll().stream().filter(task -> isPresentYear(task.getCreateTime())).count());
        //新增设备数
        centerNum.setDeviceAddCount((int) deviceLibraryDao.findAll().stream().filter(deviceLibrary -> deviceLibrary.getCreateTime()!=null&&isPresentYear(deviceLibrary.getCreateTime())).count());
        //故障率
        Set<Integer> repairDeviceIds = new HashSet<>();
        List<Task> tasks = taskDao.findAllByBusinessType(BusinessEnum.REPAIR.id).stream().filter(task -> task.getParentTaskId()==null).collect(Collectors.toList());
        List<RepairSendBill> repairSendBills = tasks.stream()
                .map(task -> repairBillService.getOne(task.getBillId()))
                .map(repairBill -> repairSendBillDao.findByDeviceRepairBillId(repairBill.getId()))
                .collect(Collectors.toList());
        for (RepairSendBill r:repairSendBills) {
            if (r.getRepairDeviceCheckDetail()!=null&&r.getRepairStatus()>0) {
                repairDeviceIds.addAll(StringSplitUtil.split(r.getRepairDeviceCheckDetail()));
            }
        }
        double num = repairDeviceIds.size();
        double faultPercent = num/centerNum.getDeviceCount()*100;
        centerNum.setFaultPercent(faultPercent);
        return centerNum;
    }

    /**
     * 获取装备维修情况数量统计
     */
    @Override
    public RepairNum getRepairNum() {
        RepairNum repairNum = new RepairNum();
        List<Task> tasks = taskDao.findAllByBusinessType(BusinessEnum.REPAIR.id).stream().filter(task -> task.getParentTaskId()==null).collect(Collectors.toList());
        List<List<RepairDetail>> repairDetails = tasks.stream()
                .map(task -> repairBillService.getOne(task.getBillId()))
                .map(repairBill -> repairDetailDao.findByDeviceRepairBillId(repairBill.getId()))
                .collect(Collectors.toList());
        int repairCount = 0;
        int completeCount = 0;
        int changeNewCount = 0;
        int noCompleteCount = 0;
        for (List<RepairDetail> l:repairDetails) {
            for (RepairDetail r:l) {
                switch (r.getRepairStatus()){
                    case 0:
                        repairCount++;
                        noCompleteCount++;
                        break;
                    case 1:
                        repairCount++;
                        noCompleteCount++;
                        break;
                    case 2:
                        repairCount++;
                        completeCount++;
                        break;
                    case 4:
                        repairCount++;
                        if (r.getNewDeviceDetailId()!=null&&r.getNewDeviceDetailId()>0){
                            changeNewCount++;
                        }
                        else {
                            noCompleteCount++;
                        }
                        break;
                    case 5:
                        repairCount++;
                        completeCount++;
                        break;
                    default:break;
                }
            }
        }
        repairNum.setChangeNewCount(changeNewCount);
        repairNum.setCompleteCount(completeCount);
        repairNum.setNoCompleteCount(noCompleteCount);
        repairNum.setRepairCount(repairCount);
        return repairNum;
    }

    /**
     * 获取装备维修情况装备统计
     */
    @Override
    public List<RepairDevice> getRepairDevices() {
        List<RepairDevice> repairDevices = new ArrayList<>();
        List<Task> tasks = taskDao.findAllByBusinessType(BusinessEnum.REPAIR.id).stream().filter(task -> task.getParentTaskId()==null).collect(Collectors.toList());
        List<List<RepairDetail>> repairDetails = tasks.stream()
                .map(task -> repairBillService.getOne(task.getBillId()))
                .map(repairBill -> repairDetailDao.findByDeviceRepairBillId(repairBill.getId()))
                .collect(Collectors.toList());
        for (List<RepairDetail> l:repairDetails) {
            for (RepairDetail r:l) {
                RepairDevice repairDevice = new RepairDevice();
                repairDevice.setLocationUnit(r.getLocationUnit());
                repairDevice.setModel(r.getModel());
                repairDevice.setType(r.getType());
                switch (r.getRepairStatus()){
                    case 0:
                        repairDevice.setRepairStatus("未完成");
                        repairDevices.add(repairDevice);
                        break;
                    case 1:
                        repairDevice.setRepairStatus("未完成");
                        repairDevices.add(repairDevice);
                        break;
                    case 2:
                        repairDevice.setRepairStatus("完成");
                        repairDevices.add(repairDevice);
                        break;
                    case 4:
                        if (r.getNewDeviceDetailId()!=null&&r.getNewDeviceDetailId()>0){
                            repairDevice.setRepairStatus("已换新");
                        }
                        else {
                            repairDevice.setRepairStatus("未完成");
                        }
                        repairDevices.add(repairDevice);
                        break;
                    case 5:
                        repairDevice.setRepairStatus("完成");
                        repairDevices.add(repairDevice);
                        break;
                    case 7:
                        repairDevice.setRepairStatus("完成");
                        repairDevices.add(repairDevice);
                        break;
                    default:break;
                }
            }
        }
        return repairDevices;
    }

    /**
     * 获取最近一次自查统计
     */
    @Override
    public List<SelfCheckNum> getSelfCheckNum() {
        List<SelfCheckNum> selfCheckNums = new ArrayList<>();
        //获取所有自查单
        List<SelfCheckBill> selfCheckBills = selfCheckBillDao.findAll();
        //获取所有市
        List<Area> areas = areaDao.findAreasByType(1);
        //获取省
        List<Area> areas2 = areaDao.findAreasByType(2);
        areas.addAll(areas2);
        //遍历市，找到最近完成的自查和核查账单
        for (Area a:areas) {
            SelfCheckNum selfCheckNum = new SelfCheckNum();
            selfCheckNum.setAreaName(a.getName());
            List<Units> units = unitsDao.findAllByAreaId(a.getId());
            if (units.size()==1) {
                //获取市单位名称
                String unitName = units.get(0).getName();
                //筛选出当前单位已完成的自查和核查账单，按更新时间排序
                List<SelfCheckBill> selfCheckBillList = selfCheckBills.stream()
                        .filter(selfCheckBill -> selfCheckBill.getCheckUnit().equals(unitName))
                        .sorted(Comparator.comparing(SelfCheckBill::getUpdateTime,Comparator.nullsLast(Date::compareTo)).reversed())
                        .collect(Collectors.toList());
                if (!selfCheckBillList.isEmpty()) {
                    SelfCheckBill s = selfCheckBillList.get(0);
                    if (s.getCheckStatus()!=3&&s.getCheckDetail()!=null) {
                        String[] strings = s.getCheckDetail().split("x");
                        for (String s1 : strings) {
                            if (s1.length() >= 2) {
                                //缺失
                                if ("0".equals(s1.substring(s1.length() - 1))) {
                                    selfCheckNum.setLoseCount(selfCheckNum.getLoseCount() + 1);
                                }
                                //无误
                                if ("1".equals(s1.substring(s1.length() - 1))) {
                                    selfCheckNum.setUnmistakableCount(selfCheckNum.getUnmistakableCount() + 1);
                                }
                                //新增
                                if ("2".equals(s1.substring(s1.length() - 1))) {
                                    selfCheckNum.setUnRegisterCount(selfCheckNum.getUnRegisterCount() + 1);
                                }
                            }
                        }
                    }
                    else if(s.getCheckStatus()==3){
                        PredicateBuilder<DeviceLibrary> predicateBuilder = Specifications.and();
                        predicateBuilder.eq("ownUnit", unitName);
                        predicateBuilder.eq("lifeStatus", 2);
                        selfCheckNum.setUnCheckCount(deviceLibraryDao.findAll(predicateBuilder.build()).size());
                    }
                }
            }
            //总数
            selfCheckNum.setSelfCheckCount(selfCheckNum.getUnCheckCount()+selfCheckNum.getLoseCount()+selfCheckNum.getUnmistakableCount()+selfCheckNum.getUnRegisterCount());
            selfCheckNums.add(selfCheckNum);
        }
        return selfCheckNums;
    }

    /**
     * 专管员统计
     */
    @Override
    public List<UserDateScreen> selectUserDataScreen() {
        List<UserDateScreen> list=new ArrayList<>();
        Map<Integer,UserDateScreen> map=new HashMap<>();
        //获取所有市
        List<Area> areas = areaDao.findAreasByType(2);
        //获取省
        List<Area> areas2 = areaDao.findAreasByType(1);
        areas.addAll(areas2);
//        List<Integer> areaIds = areas.stream().map(Area::getId).collect(Collectors.toList());
//        List<Integer> levels=new ArrayList<>();
//        levels.add(1);
//        levels.add(2);
        areas.forEach(area -> {
            List<Integer> unitIds= unitsDao.findAllByAreaId(area.getId()).stream().map(Units::getUnitId).collect(Collectors.toList());
            List<User> users= userDao.findAllByUnitsIdIn(unitIds);
            if (users.size()>0) {
                users.forEach(
                        user -> {
                            if (user.getTrainStatus()!=5) {
                                UserDateScreen userDateScreen = new UserDateScreen();
                                if (map.containsKey(area.getId())) {
                                    userDateScreen = map.get(area.getId());
                                }
                                switch (user.getTrainStatus()) {
                                    case 0:
                                        userDateScreen.setHadBeenTraining(userDateScreen.getHadBeenTraining() + 1);
                                        break;
                                    case 1:
                                        userDateScreen.setExpired(userDateScreen.getExpired() + 1);
                                        break;
                                    case 2:
                                        userDateScreen.setNoTraining(userDateScreen.getNoTraining() + 1);
                                        break;
                                    case 3:
                                        userDateScreen.setHadBeenTraining(userDateScreen.getHadBeenTraining() + 1);
                                        break;
                                    default:
                                        log.info("[用户] 未找到对应的培训状态{}", user.getTrainStatus());
                                }
                                userDateScreen.setUnitName(area.getName());
                                map.put(area.getId(), userDateScreen);
                            }
                        }
                );
            }
            else {
                UserDateScreen userDateScreen = new UserDateScreen();
                userDateScreen.setUnitName(area.getName());
                map.put(area.getId(), userDateScreen);
            }
        });
        for (Integer areaId:map.keySet()){
            UserDateScreen userDateScreen=map.get(areaId);
            list.add(userDateScreen);
        }
        return list;
    }

    private Integer getMonth(Date date){
        return date.getMonth()+1;
    }

    private Boolean isPresentYear(Date date){
        return new Date().getYear()==date.getYear();
    }
}
