package cn.com.countrygarden.bi.main.service.eba.impl;

import cn.com.countrygarden.bi.main.dao.eba.TbmMaintainTaskMapper;
import cn.com.countrygarden.bi.main.model.eba.TbmMaintainTask;
import cn.com.countrygarden.bi.main.model.eba.TbmMaintainTaskResult;
import cn.com.countrygarden.bi.main.service.eba.TbmMaintainTaskService;
import cn.com.countrygarden.bi.main.core.AbstractService;
import cn.com.countrygarden.bi.main.util.ChinaGeoUtil;
import cn.com.countrygarden.bi.main.util.DateUtil;
import cn.com.countrygarden.bi.main.util.NumberUtil;
import cn.com.countrygarden.bi.main.util.RedisCacheUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;


@Service
@Transactional
public class TbmMaintainTaskServiceImpl extends AbstractService<TbmMaintainTask> implements TbmMaintainTaskService {
    @Resource
    private TbmMaintainTaskMapper mapper;


    /**
     * 统计全部
     * 及时完成单数、及时接单数、单数、有偿单数、有偿金额、已完成单数、未完成单数
     *
     * @return
     */
    public Map<String, Object> aggregate() {
        return mapper.aggregate(new HashMap<>());
    }

    /**
     * 汇总工程人数
     *
     * @return
     */
    public TbmMaintainTaskResult aggregateEngineering() {
        return mapper.aggregateEngineering(new HashMap<>());
    }

    /**
     * 获取工程人员总数
     *
     * @return
     */
    public int getEngineeringQuatity() {
        TbmMaintainTaskResult enginer = aggregateEngineering();
        return enginer.getEngineering();
    }

    /**
     * 统计今日
     * 及时完成单数、及时接单数、单数、有偿单数、有偿金额、已完成单数、未完成单数
     *
     * @return
     */
    public Map<String, Object> aggregateToday() {
        return mapper.aggregate(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getStartOfToday());
            put("before", DateUtil.getEndOfToday());
        }});
    }

    /**
     * 统计昨日
     * 及时完成单数、及时接单数、单数、有偿单数、有偿金额、已完成单数、未完成单数
     *
     * @return
     */
    public Map<String, Object> aggregateYesterday() {
        return aggregateYesterdayFromMapper();
    }

    /**
     * 统计昨日并缓存
     * 及时完成单数、及时接单数、单数、有偿单数、有偿金额、已完成单数、未完成单数
     *
     * @return
     */
    public Map<String, Object> aggregateYesterdayFromCache() {
        Map<String, String> param = new HashMap<>();
        Function<Map<String, String>, Map<String, Object>> function = p -> aggregateYesterdayFromMapper();

        return RedisCacheUtils.rememberMap(
                "datav:eba:wo:quantity:aggregate:yesterday",
                7200 /* 2 * 60 * 60 */,
                param,
                function
        );
    }

    /**
     * 统计本月
     * 及时完成单数、及时接单数、单数、有偿单数、有偿金额、已完成单数、未完成单数
     *
     * @return
     */
    public Map<String, Object> aggregateThisMonth() {
        return mapper.aggregate(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfMonth());
            put("before", DateUtil.getLastDayOfMonth());
        }});
    }

    /**
     * 本月个区域接单统计
     *
     * @return
     */
    public List<Map<String, Object>> aggregateThisMonthByOrgan() {
        List<TbmMaintainTaskResult> aggres = mapper.aggregateByOrgan(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfMonth());
            put("before", DateUtil.getLastDayOfMonth());
        }});

        return rankingAggregateByOrgan(aggres);
    }

    /**
     * 上月个区域接单统计
     *
     * @return
     */
    public List<Map<String, Object>> aggregatePreviousMonthByOrgan() {
        List<TbmMaintainTaskResult> aggres = mapper.aggregateByOrgan(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfPreviousMonth());
            put("before", DateUtil.getLastDayOfPreviousMonth());
        }});

        return rankingAggregateByOrgan(aggres);
    }

    /**
     * 本月工单来源统计
     *
     * @return
     */
    public List<TbmMaintainTaskResult> aggregateThisMonthBySource() {
        return mapper.aggregateBySource(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfMonth());
            put("before", DateUtil.getLastDayOfMonth());
        }});
    }

    /**
     * 本月工单分类统计
     *
     * @return
     */
    public List<TbmMaintainTaskResult> aggregateThisMonthByCategory() {
        return mapper.aggregateByCategory(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfMonth());
            put("before", DateUtil.getLastDayOfMonth());
        }});
    }

    /**
     * 本年月度工单统计
     *
     * @return
     */
    public List<TbmMaintainTaskResult> aggregateThisYearByMonth() {
        return mapper.aggregateByMonth(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfThisYear() + " 00:00:00");
        }});
    }

    /**
     * 实时工单
     *
     * @return
     */
    public List<TbmMaintainTaskResult> realtime(int limit) {
        return mapper.realtime(new HashMap<String, Object>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfThisYear() + " 00:00:00");
            put("limit", Math.max(0, limit));
        }});
    }

    /**
     * 实时工单
     *
     * @return
     */
    public List<TbmMaintainTaskResult> realtime(int taskState, int limit) {
        return mapper.realtime(new HashMap<String, Object>() {{
            put("isAvail", "1");
            put("after", DateUtil.getFirstDayOfThisYear() + " 00:00:00");
            put("taskState", taskState);
            put("limit", Math.max(0, limit));
        }});
    }


    /**
     * 从 mapper 中获取昨日统计
     *
     * @return
     */
    private Map<String, Object> aggregateYesterdayFromMapper() {
        return mapper.aggregate(new HashMap<String, String>() {{
            put("isAvail", "1");
            put("after", DateUtil.getStartOfYesterday());
            put("before", DateUtil.getEndOfYesterday());
        }});
    }

    /**
     * 本月个区域接单统计排行
     * @param aggres
     * @return
     */
    private List<Map<String, Object>> rankingAggregateByOrgan(List<TbmMaintainTaskResult> aggres) {
        List<Map<String, Object>> resultList = new ArrayList<>();

        if (aggres.isEmpty()) {
            return resultList;
        }

        int maxQuantity = 0;
        for (TbmMaintainTaskResult aggre : aggres) {
            Map<String, Object> item = new HashMap<>();
            int finishedInTime = aggre.getFinishedInTime();
            int takingInTime = aggre.getTakingInTime();
            int quantity = aggre.getQuantity();
            int curDateQuantity = aggre.getCurDateQuantity();
            // 最高接单数
            maxQuantity = Math.max(maxQuantity, quantity);

            float finishedInTimeRateRate = NumberUtil.percentage(finishedInTime, quantity);
            float takingInTimeRate = NumberUtil.percentage(takingInTime, quantity);
            item.put("finishedInTime", finishedInTime);
            item.put("finishedInTimeRate", finishedInTimeRateRate);
            item.put(
                    "finishedInTimeRateText",
                    NumberUtil.simpleFormat(finishedInTimeRateRate) + "%"
            );
            item.put("takingInTime", takingInTime);
            item.put("takingInTimeRate", takingInTimeRate);
            item.put(
                    "takingInTimeRateText",
                    NumberUtil.simpleFormat(takingInTimeRate) + "%"
            );
            item.put("quantity", quantity);
            item.put("curDateQuantity", curDateQuantity);
            item.put("quantityText", NumberUtil.simpleFormat(quantity));

            String organName = aggre.getOrganName().trim();
            item.put("organ_name", organName);

            List<String> geo = ChinaGeoUtil.getOrganProvinceGeo(organName);
            if (geo == null || geo.isEmpty()) {
                item.put("lng", "");
                item.put("lat", "");
            } else {
                item.put("lng", geo.get(0));
                item.put("lat", geo.get(1));
            }

            resultList.add(item);
        }

        rsortList(resultList, "takingInTimeRate");

        int ranking = 1;
        int smallCap = (int) Math.ceil(maxQuantity / 3);
        int middleCap = smallCap * 2;

        for (Map<String, Object> item : resultList) {
            item.put("rank", ranking++);
            int quantity = Integer.parseInt(item.getOrDefault("quantity", "0").toString());
            if (quantity <= smallCap) {
                item.put("type", "1");
            } else if (quantity > smallCap && quantity <= middleCap) {
                item.put("type", "2");
            } else {
                item.put("type", "3");
            }
        }

        return resultList;
    }

    /**
     * 按特定键值倒叙排序
     *
     * @param list
     * @param key
     */
    private void rsortList(List<Map<String, Object>> list, String key) {
        Collections.sort(list, (Map<String, Object> left, Map<String, Object> right) -> {
                    float l = (float) left.get(key);
                    float r = (float) right.get(key);

                    // 倒叙排序
                    if (l < r) {
                        return 1;
                    } else if (l > r) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
        );
    }
}
