package com.bonus.canteen.core.screening.service;

import com.bonus.canteen.core.screening.dto.DataScreenDTO;
import com.bonus.canteen.core.screening.mapper.DataScreeningMapper;
import com.bonus.canteen.core.screening.vo.EchartsVO;
import com.bonus.canteen.core.screening.vo.SingleModelVO;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 19814
 */
@Service
public class DataScreeningServiceImpl implements DataScreeningService {
    @Resource
    private DataScreeningMapper mapper;

    private static final Logger log = LoggerFactory.getLogger(DataScreeningServiceImpl.class);

    private static final String TURNOVER = "Turnover";
    private static final String ORDER = "Order";
    private static final String PERSON = "Person";
    private static final String DISH = "Dish";
    private static final int MAX_LAST_DAY = -29;

    /**
     * 获取数据总览
     *
     * @return 数据总览结果
     */
    @Override
    public AjaxResult getDataScreeningModel() {
        int lastDay = -1;
        List<SingleModelVO> list = new ArrayList<>();
        String currentDate = DateUtils.getDate();
        String yesterday = getLastDate(-1);
        //获取上一个有食堂订单的日期
        yesterday = getLastDate(lastDay, yesterday);
        // 查询各项数据
        addSingleItem("今日食堂营业额（元）", currentDate, yesterday, list, 11, TURNOVER);
        addSingleItem("今日食堂订单量（个）", currentDate, yesterday, list, 11, ORDER);
        addSingleItem("今日就餐人数（个）", currentDate, yesterday, list, 11, PERSON);
        addSingleItem("今日菜品数量（个）", currentDate, yesterday, list, -1, DISH);
        addSingleItem("今日超市营业额（元）", currentDate, yesterday, list, 4, TURNOVER);
        addSingleItem("今日超市订单量（个）", currentDate, yesterday, list, 4, ORDER);
        return AjaxResult.success(list);
    }

    /**
     * 获取上一个有食堂订单的日期
     *
     * @param lastDay 昨日日期
     * @return 昨日日期
     */
    private String getLastDate(int lastDay, String yesterday) {
        while (lastDay >= MAX_LAST_DAY) {
            yesterday = getLastDate(lastDay);
            SingleModelVO yesterdayVO = fetchDataByType(yesterday, 11, TURNOVER);
            if (yesterdayVO.getNum().compareTo(BigDecimal.ZERO) != 0) {
                break;
            }
            lastDay--;
        }
        return yesterday;
    }

    /**
     * 添加单项数据
     *
     * @param name          名称
     * @param currentDate   今日日期
     * @param yesterdayData 昨日日期
     * @param list          数据列表
     * @param orderType     订单类型
     * @param type          数据类型
     */
    private void addSingleItem(String name, String currentDate, String yesterdayData, List<SingleModelVO> list, int orderType, String type) {
        SingleModelVO today = fetchDataByType(currentDate, orderType, type);
        SingleModelVO yesterday = fetchDataByType(yesterdayData, orderType, type);
        today.setLastDate(yesterdayData);
        today.setName(name);
        calculateRate(today, yesterday, type);
        list.add(today);
    }

    /**
     * 根据数据类型获取数据
     *
     * @param date      日期
     * @param orderType 订单类型
     * @param type      数据类型
     * @return 数据
     */
    private SingleModelVO fetchDataByType(String date, int orderType, String type) {
        switch (type) {
            case ORDER:
                return mapper.selectOrder(date, orderType);
            case TURNOVER:
                return mapper.selectTurnover(date, orderType);
            case PERSON:
                return mapper.selectPerson(date, orderType);
            case DISH:
                return mapper.selectDish(date);
            default:
                return new SingleModelVO();
        }
    }

    /**
     * 计算今日与昨日的比率
     *
     * @param today    今日数据
     * @param yesterday 昨日数据
     * @param type     数据类型
     */
    private void calculateRate(SingleModelVO today, SingleModelVO yesterday, String type) {
        BigDecimal yesterdayNum = Optional.ofNullable(yesterday.getNum()).orElse(BigDecimal.ZERO);
        BigDecimal todayNum = Optional.ofNullable(today.getNum()).orElse(BigDecimal.ZERO);

        if (yesterdayNum.compareTo(BigDecimal.ZERO) == 0) {
            today.setRate(todayNum.compareTo(BigDecimal.ZERO) == 0 ? "0.0" : "100.0");
        } else {
            BigDecimal rate = todayNum.subtract(yesterdayNum)
                    .divide(yesterdayNum, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100));
            today.setRate(String.format("%.2f", rate));
        }

        if (TURNOVER.equals(type)) {
            today.setNum(todayNum.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        }
    }

    /**
     * 获取食堂订单及销量趋势
     *
     * @param dataScreenDTO 数据筛选DTO
     * @return 订单及销量趋势结果
     */
    @Override
    public AjaxResult getCanteenOrdersAndSalesTrends(DataScreenDTO dataScreenDTO) {
        return getOrdersAndSalesTrends(dataScreenDTO, true);
    }

    /**
     * 获取商超订单及销量趋势
     *
     * @param dataScreenDTO 数据筛选DTO
     * @return 订单及销量趋势结果
     */
    @Override
    public AjaxResult getSupermarketOrderAndSalesTrend(DataScreenDTO dataScreenDTO) {
        return getOrdersAndSalesTrends(dataScreenDTO, false);
    }

    /**
     * 获取食堂订单及销量趋势
     *
     * @param dataScreenDTO 数据筛选DTO
     * @return 订单及销量趋势结果
     */
    private AjaxResult getOrdersAndSalesTrends(DataScreenDTO dataScreenDTO, boolean isCanteen) {
        String date = getLastDate("2".equals(dataScreenDTO.getType()) ? -29 : -6);
        List<EchartsVO> list = isCanteen
                ? mapper.getCanteenOrdersAndSalesTrends(date, DateUtils.getDate())
                : mapper.getSupermarketOrderAndSalesTrend(date, DateUtils.getDate());

        List<String> dateList = getDatesBetween(date, DateUtils.getDate(), "yyyy-MM-dd");
        // 将list中的数据放入map中，key为orderDate，value为EchartsVO 提升查询效率
        Map<String, EchartsVO> dataMap = list.stream()
                .collect(Collectors.toMap(EchartsVO::getOrderDate, vo -> vo, (a, b) -> a));

        List<EchartsVO> result = dateList.stream().map(dateStr -> {
            EchartsVO echartsVO = dataMap.getOrDefault(dateStr, new EchartsVO());
            echartsVO.setOrderDate(dateStr);
            echartsVO.setSalesValue(Optional.ofNullable(echartsVO.getSalesValue())
                    .map(value -> new BigDecimal(value).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString())
                    .orElse("0"));
            echartsVO.setOrderValue(Optional.ofNullable(echartsVO.getOrderValue()).orElse("0"));
            return echartsVO;
        }).sorted(Comparator.comparing(EchartsVO::getOrderDate)).collect(Collectors.toList());

        return AjaxResult.success(result);
    }

    /**
     * 获取本日菜品销量排名
     *
     * @return 本日菜品销量排名结果
     */
    @Override
    public AjaxResult getThisMonthDishSalesRanking() {
        String date = getLastDate(-29);
        return AjaxResult.success(mapper.getThisMonthDishSalesRanking(date, DateUtils.getDate()));
    }
    /**
     * 获取订单类型占比
     *
     * @param dataScreenDTO 数据筛选DTO
     * @return 订单类型占比结果
     */
    @Override
    public AjaxResult getProportionOfOrderTypes(DataScreenDTO dataScreenDTO) {
        String date = getLastDate("2".equals(dataScreenDTO.getType()) ? -29 : -6);
        SingleModelVO superMarketOrder = mapper.selectOrderByDate(date,DateUtils.getDate(), 4);
        SingleModelVO canteenOrder = mapper.selectOrderByDate(date,DateUtils.getDate(), 11);
        SingleModelVO preOrderMealOrder = mapper.selectOrderByDate(date,DateUtils.getDate(), 2);

        BigDecimal total = superMarketOrder.getNum().add(canteenOrder.getNum()).add(preOrderMealOrder.getNum());

        calculateProportion(superMarketOrder, total, "超市订单");
        calculateProportion(canteenOrder, total, "食堂订单");
        calculateProportion(preOrderMealOrder, total, "外卖订单");
        return AjaxResult.success(Arrays.asList(superMarketOrder, canteenOrder, preOrderMealOrder));
    }
    /**
     * 计算订单占比
     *
     * @param order  订单
     * @param total  总订单量
     * @param name   订单名称
     */
    private void calculateProportion(SingleModelVO order, BigDecimal total, String name) {
        order.setName(name);
        if (total.compareTo(BigDecimal.ZERO) == 0) {
            order.setRate("0.0");
        } else {
            BigDecimal rate = order.getNum().divide(total, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100));
            order.setRate(String.format("%.2f", rate));
        }
    }
    /**
     * 获取指定日期的指定格式
     *
     * @param day   相对天数
     * @return 日期字符串
     */
    public static String getLastDate(int day) {
        Calendar calendar = Calendar.getInstance();
        // 日期减去一天
        calendar.add(Calendar.DATE, day);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取指定日期范围内的所有日期
     *
     * @param startStr 开始日期字符串
     * @param endStr   结束日期字符串
     * @param pattern  日期格式
     * @return 日期列表
     */
    public static List<String> getDatesBetween(String startStr, String endStr, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        List<String> dates = new ArrayList<>();
        try {
            Date startDate = sdf.parse(startStr);
            Date endDate = sdf.parse(endStr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            while (!calendar.getTime().after(endDate)) {
                dates.add(sdf.format(calendar.getTime()));
                calendar.add(Calendar.DATE, 1);
            }
        } catch (Exception e) {
            log.error("日期转换异常",  e);
        }
        return dates;
    }
}
