package com.yuchen.saas.park.service.fault.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuchen.saas.park.api.entity.fault.EquipmentStatus;
import com.yuchen.saas.park.api.util.DeviceDataUtils;
import com.yuchen.saas.park.service.fault.mapper.EquipmentPictureAnalyseMapper;
import com.yuchen.saas.park.service.fault.service.EquipmentBreakdownCountService;
import com.yuchen.saas.park.service.fault.service.EquipmentBreakdownHistoryService;
import com.yuchen.saas.park.service.fault.service.EquipmentPictureAnalyseService;
import com.yuchen.saas.park.service.fault.service.EquipmentStatusService;
import org.nest.springwrap.core.tool.api.R;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.*;

/**
 * @Author: 肖润飞
 * @CreateTime: 2022/10/21 10:37
 * @Description: 设备故障统计接口
 * @Version: 1.0
 */
@Service
public class EquipmentBreakdownCountServiceImpl implements EquipmentBreakdownCountService {

    @Resource
    private EquipmentStatusService equipmentStatusService;

    @Resource
    private EquipmentPictureAnalyseMapper analyseMapper;

    @Resource
    private EquipmentBreakdownHistoryService historyService;

    @Resource
    private EquipmentPictureAnalyseService analyseService;

    @Resource
    private DeviceDataUtils deviceDataUtils;

    @Override
    public R total(Long parkId) {
        Map<String, Object> map = new HashMap<>();
        LambdaQueryWrapper<EquipmentStatus> query = Wrappers.lambdaQuery();
        query.eq(EquipmentStatus::getStatus, 0);
        int normal = equipmentStatusService.count(query);
        query.clear();
        query.eq(EquipmentStatus::getStatus, 1);
        int abnormal = equipmentStatusService.count(query);
        int deviceTotal = deviceDataUtils.getDeviceTotal(parkId.toString());
        map.put("normal", normal);
        map.put("abnormal", abnormal);
        map.put("total", deviceTotal);
        map.put("underReport", deviceTotal - normal - abnormal);
        return R.data(map);
    }

    /**
     * 趋势以排名统计
     *
     * @param parkId   园区id
     * @param dateType 时间类型 1: 近七天 ; 2: 近30天 ; 3:近一年
     * @return
     */
    @Override
    public R trentAndRank(Long parkId, String dateType) {
        Map<String, Object> resMap = new HashMap<>();
        Date date = new Date();
        DateTime lastDayEndTime = DateUtil.endOfDay(DateUtil.offsetDay(date, -1));
        List<Object> trent = null;//趋势数据
        List<Object> time = new ArrayList<>();//趋势数据
        List<Map<String, Object>> rank = new ArrayList<>();//排名数据
        switch (dateType) {
            case "1"://统计近七天数据
                rank = historyService.deviceBreakdownNum(parkId, DateUtil.beginOfDay(DateUtil.offsetDay(lastDayEndTime, -7)), lastDayEndTime);//获得排名数据

                Integer[] week = new Integer[7];
                Arrays.fill(week, 0);
                trent = Arrays.asList(week);
                this.oneWeekBreakdownNum(parkId, lastDayEndTime, trent, time);//获得趋势数据
                break;
            case "2"://统计近30天数据
                rank = historyService.deviceBreakdownNum(parkId, DateUtil.beginOfDay(DateUtil.offsetDay(lastDayEndTime, -30)), lastDayEndTime);

                Integer[] month = new Integer[30];
                Arrays.fill(month, 0);
                trent = Arrays.asList(month);
                this.oneMonthBreakdownNum(parkId, lastDayEndTime, trent, time);//获得趋势数据
                break;
            case "3"://统计近一年数据
                rank = historyService.deviceBreakdownNum(parkId, DateUtil.beginOfDay(DateUtil.offsetMonth(lastDayEndTime, -12)), lastDayEndTime);

                Integer[] year = new Integer[12];
                Arrays.fill(year, 0);
                trent = Arrays.asList(year);
                this.oneYearBreakdownNum(parkId, date, trent, time);//获得趋势数据
                break;
        }
        int num = rank.stream().mapToInt(map -> Integer.parseInt(map.get("num") == null ? "0" : map.get("num").toString())).sum();
        if (num != 0) {
            DecimalFormat df = new DecimalFormat("0.00");
            for (Map<String, Object> map : rank) {
                long valueNum = map.get("num") == null ? 0L : (long) map.get("num");
                String rate = df.format(((float) valueNum / num) * 100);
                map.put("rate", rate);
            }
        } else {
            rank.stream().map(map -> map.put("rate", "0"));
        }
        resMap.put("trent", trent);
        resMap.put("rank", rank);
        resMap.put("time", time);
        return R.data(resMap);
    }

    /**
     * 设备画像占比
     *
     * @param parkId
     * @return
     */
    @Override
    public R pictureRate(Long parkId) {
        //根据园区id
        R pictureRate = analyseService.pictureRate(parkId);
        return pictureRate;
    }

    /**
     * 频繁误报统计
     *
     * @param parkId
     * @return
     */

    @Override
    public R pictureCode(Long parkId, String pictureCode) {
        Map<String, Object> res = new HashMap<>();
        List<Map<String, Object>> maps = analyseMapper.analysePictureCode(parkId, pictureCode);
        String rate = null;
        if (maps != null && maps.size() > 0) {
            DecimalFormat df = new DecimalFormat("0.00");
            rate = df.format((float) maps.size() * 100 / deviceDataUtils.getDeviceTotal(parkId.toString()));
        }
        res.put("rate", rate);
        res.put("rankList", maps);
        return R.data(res);
    }

    private void oneWeekBreakdownNum(Long parkId, Date lastDayEndTime, List<Object> trent, List<Object> time) {
        Date startTime;
        Date endTime;

        for (int i = 6; i >= 0; i--) {
            startTime = DateUtil.beginOfDay(DateUtil.offsetDay(lastDayEndTime, -i));
            endTime = DateUtil.endOfDay(DateUtil.offsetDay(lastDayEndTime, -i));
            time.add(DateUtil.format(endTime, "MM.dd"));
            List<Map<String, Object>> list = historyService.deviceBreakdownNum(parkId, startTime, endTime);
            if (list != null && list.size() > 0) {
                int num = list.stream().mapToInt(map -> Integer.parseInt(map.get("num") == null ? "0" : map.get("num").toString())).sum();
                trent.set(6 - i, num);
            }
        }
    }

    private void oneMonthBreakdownNum(Long parkId, Date lastDayEndTime, List<Object> trent, List<Object> time) {
        Date startTime;
        Date endTime;
        for (int i = 29; i >= 0; i--) {
            startTime = DateUtil.beginOfDay(DateUtil.offsetDay(lastDayEndTime, -i));
            endTime = DateUtil.endOfDay(DateUtil.offsetDay(lastDayEndTime, -i));
            time.add(DateUtil.format(endTime, "MM.dd"));
            List<Map<String, Object>> list = historyService.deviceBreakdownNum(parkId, startTime, endTime);
            if (list != null && list.size() > 0) {
                int num = list.stream().mapToInt(map -> Integer.parseInt(map.get("num") == null ? "0" : map.get("num").toString())).sum();
                trent.set(29 - i, num);
            }
        }
    }

    private void oneYearBreakdownNum(Long parkId, Date date, List<Object> trent, List<Object> time) {
        Date startTime;
        Date endTime;
        for (int i = 12; i > 0; i--) {
            DateTime lastMonth = DateUtil.offsetMonth(date, -i);//上一个月时间
            startTime = DateUtil.beginOfMonth(lastMonth);
            endTime = DateUtil.endOfMonth(lastMonth);
            time.add(DateUtil.format(endTime, "MM"));
            List<Map<String, Object>> list = historyService.deviceBreakdownNum(parkId, startTime, endTime);
            if (list != null && list.size() > 0) {
                int num = list.stream().mapToInt(map -> Integer.parseInt(map.get("num") == null ? "0" : map.get("num").toString())).sum();
                trent.set(12 - i, num);
            }
        }
    }

}