package com.xxfc.platform.order.biz;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.ace.cache.annotation.Cache;
import com.ace.cache.annotation.CacheClear;
import com.github.wxiaoqi.security.admin.entity.BaseUserMemberLevel;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.auth.PageResult;
import com.google.common.collect.Maps;
import com.xxfc.platform.order.Utils.OrderDateUtils;
import com.xxfc.platform.order.contant.enumerate.OrderInquiryType;
import com.xxfc.platform.order.contant.enumerate.OrderStatusEnum;
import com.xxfc.platform.order.contant.enumerate.OrderTypeEnum;
import com.xxfc.platform.order.contant.enumerate.RefundStatusEnum;
import com.xxfc.platform.order.entity.*;
import com.xxfc.platform.order.mapper.OrderStatisticsMapper;
import com.xxfc.platform.order.pojo.*;
import com.xxfc.platform.order.pojo.order.OrderFullDTO;
import com.xxfc.platform.order.pojo.order.OrderFullVO;
import com.xxfc.platform.order.rest.background.BgStatisticsController;
import com.xxfc.platform.vehicle.constant.RedisKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_TRUE;


/**
 * @author Administrator
 */
@Service
@Slf4j
public class OrderStatisticsBiz extends BaseBiz<OrderStatisticsMapper, OrderStatistics> {
    @Autowired
    private DailyVehicleOrderStatisticsBiz vehicleBiz;
    @Autowired
    private DailyTravelOrderStatisticsBiz TravelBiz;
    @Autowired
    private DailyMembersOrderStatisticsBiz membersBiz;

    @Autowired
    private DailyVehicleOrderStatisticsBiz vehicleStatisticsBiz;
    @Autowired
    private DailyTravelOrderStatisticsBiz travelStatisticsBiz;
    @Autowired
    private DailyMembersOrderStatisticsBiz membersStatisticsBiz;
    @Autowired
    OrderRentVehicleBiz orderRentVehicleBiz;


    public HomePageOrderData getTotalOrder(List<Integer> companyIds, Integer dataAll) {
        HomePageOrderData result = new HomePageOrderData();
        ArrayList<HomePageOrderData> list = new ArrayList<>();
        list.add(getVehicleHomePageOrderData(companyIds));
        list.add(getTourHomePageOrderData(companyIds));
        if (1==dataAll) {
            list.add(getMemberHomePageOrderData(companyIds));
        }
        result.setTotalOrders(list.stream().map(HomePageOrderData::getTotalOrders).reduce(BigDecimal.ZERO, BigDecimal::add));
        result.setTotalOutstandingDeposit(list.stream().map(HomePageOrderData::getTotalOutstandingDeposit).reduce(BigDecimal.ZERO, BigDecimal::add));
        result.setAdditionalIndemnity(list.stream().map(HomePageOrderData::getAdditionalIndemnity).reduce(BigDecimal.ZERO, BigDecimal::add));
        result.setTotalOrders(new BigDecimal(167260));
        return result;
    }

    /**
     * 会员数据
     *
     * @param companyIds
     * @return
     */
    public HomePageOrderData getMemberHomePageOrderData(List<Integer> companyIds) {
        //今天之前的数据
        OrderStatistics member = membersBiz.findAll(companyIds);
        log.error("member:"+member);
        //当天的数据
        OrderStatistics sameDayData = getMemberOrderDataOfTheDay(companyIds);
        log.error("member:sameDayData:"+sameDayData);

        if (member == null) {
            member = new OrderStatistics();
        }

        add(member, sameDayData);

        OrderStatistics finalMember = member;
        HomePageOrderData data = new HomePageOrderData() {{
            setTotalOrders(finalMember.getTotalGmv());
        }};
        return data;
    }

    /**
     * 获取会员订单当天数据
     *
     * @param companyIds
     * @return
     */
    public OrderStatistics getMemberOrderDataOfTheDay(List<Integer> companyIds) {
        OrderStatistics member = new OrderStatistics();
        DailyMembersOrderStatistics statistics = membersStatisticsBiz.statistics(new Term(OrderTypeEnum.MEMBER.getCode(), 0, 1, null, null, companyIds));
        if (statistics == null) {
            return new OrderStatistics();
        }

        //加入会员订单收入
        member.setTotalGmv(member.getTotalGmv().add(statistics.getGmv()));
        return member;
    }


    //加上当天数据
    private void add(OrderStatistics original, OrderStatistics add) {
        original.setTotalGmv(original.getTotalGmv().add(add.getTotalGmv()));
        original.setTotalReturnGmv(original.getTotalReturnGmv().add(add.getTotalReturnGmv()));
        original.setTotalSecurityDeposit(original.getTotalSecurityDeposit().add(add.getTotalSecurityDeposit()));
        original.setTotalRefundSecurityDeposit(original.getTotalRefundSecurityDeposit().add(add.getTotalRefundSecurityDeposit()));
        original.setTotalDefaultMoney(original.getTotalDefaultMoney().add(add.getTotalDefaultMoney()));
        original.setTotalOrderCompensation(original.getTotalOrderCompensation().add(add.getTotalOrderCompensation()));
        original.setTotalCompensation(original.getTotalCompensation().add(add.getTotalCompensation()));
        original.setTotalForfeit(original.getTotalForfeit().add(add.getTotalForfeit()));
    }


    /**
     * 旅游数据
     *
     * @param companyIds
     * @return
     */
    public HomePageOrderData getTourHomePageOrderData(List<Integer> companyIds) {
        //今天之前的数据
        OrderStatistics tour = TravelBiz.findAll(companyIds);
        log.error("tour:"+tour);
        if (tour == null) {
            tour = new OrderStatistics();
        }
        OrderStatistics sameDayData = getTourOrderDataOfTheDay(companyIds);
        log.error("tour:sameDayData:"+sameDayData);
        add(tour, sameDayData);
        OrderStatistics finalTour = tour;
        HomePageOrderData data = new HomePageOrderData() {{
            setTotalOrders(finalTour.getTotalGmv().subtract(finalTour.getTotalReturnGmv()));
            setAdditionalIndemnity(finalTour.getTotalDefaultMoney());
        }};
        return data;
    }

    /**
     * 获取租车订单当天数据
     *
     * @param companyIds
     * @return
     */
    public OrderStatistics getTourOrderDataOfTheDay(List<Integer> companyIds) {
        OrderStatistics tour = new OrderStatistics();

        //当天数据
        List<DailyTravelOrderStatistics> record = travelStatisticsBiz.getDailyTravelOrderStatistics(new Term(OrderTypeEnum.TOUR.getCode(), 0, 1, null, null, companyIds));
        if (CollectionUtils.isEmpty(record)) {
            return new OrderStatistics();
        }
        //加入当天旅游路线订单总和
        tour.setTotalGmv(tour.getTotalGmv().add(record.parallelStream().map(DailyTravelOrderStatistics::getGmv).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入当天退还订单总和
        tour.setTotalReturnGmv(tour.getTotalReturnGmv().add(record.parallelStream().map(DailyTravelOrderStatistics::getReturnGmv).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入当违约总和
        tour.setTotalDefaultMoney(tour.getTotalDefaultMoney().add(record.parallelStream().map(DailyTravelOrderStatistics::getDefaultMoney).reduce(BigDecimal.ZERO, BigDecimal::add)));
        return tour;
    }

    /**
     * 车辆数据
     *
     * @param companyIds
     * @return
     */
    public HomePageOrderData getVehicleHomePageOrderData(List<Integer> companyIds) {
        //今天之前的数据
        OrderStatistics vehicle = vehicleBiz.findAll(companyIds);
        log.error("vehicle:"+vehicle);
        if (vehicle == null) {
            vehicle = new OrderStatistics();
        }
        OrderStatistics sameDayData = getVehicleOrderDataOfTheDay(companyIds);
        log.error("vehicle:sameDayData:"+sameDayData);
        add(vehicle, sameDayData);

        OrderStatistics finalVehicle = vehicle;
        HomePageOrderData data = new HomePageOrderData() {{
            setTotalOrders(finalVehicle.getTotalGmv().subtract(finalVehicle.getTotalReturnGmv()));
            setAdditionalIndemnity(finalVehicle.getTotalCompensation()
                    .add(finalVehicle.getTotalForfeit())
                    .add(finalVehicle.getTotalDefaultMoney())
                    .add(finalVehicle.getTotalOrderCompensation()));
            setTotalOutstandingDeposit(finalVehicle.getTotalSecurityDeposit()
                    .subtract(finalVehicle.getTotalRefundSecurityDeposit())
                    .subtract(getAdditionalIndemnity()));
        }};
        return data;

    }

    /**
     * 获取车来个你当天数据
     *
     * @param companyIds
     * @return
     */
    public OrderStatistics getVehicleOrderDataOfTheDay(List<Integer> companyIds) {
        OrderStatistics vehicle = new OrderStatistics();
        //当天的数据
        List<DailyVehicleOrderStatistics> record = vehicleStatisticsBiz.getDailyVehicleOrderRecord(new Term(OrderTypeEnum.RENT_VEHICLE.getCode(), 0, 1, null, null, companyIds));

        if (CollectionUtils.isEmpty(record)) {
            return new OrderStatistics();
        }
        //加入当天租车订单总和
        vehicle.setTotalGmv(vehicle.getTotalGmv().add(record.parallelStream().map(DailyVehicleOrderStatistics::getGmv).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入当天退还订单总和
        vehicle.setTotalReturnGmv(vehicle.getTotalReturnGmv().add(record.parallelStream().map(DailyVehicleOrderStatistics::getReturnGmv).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入当违约总和
        vehicle.setTotalDefaultMoney(vehicle.getTotalDefaultMoney().add(record.parallelStream().map(DailyVehicleOrderStatistics::getDefaultMoney).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入当天押金总和
        vehicle.setTotalSecurityDeposit(vehicle.getTotalSecurityDeposit().add(record.parallelStream().map(DailyVehicleOrderStatistics::getSecurityDeposit).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入退还押金总和
        vehicle.setTotalRefundSecurityDeposit(vehicle.getTotalRefundSecurityDeposit().add(record.parallelStream().map(DailyVehicleOrderStatistics::getRefundSecurityDeposit).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入赔偿
        vehicle.setTotalCompensation(vehicle.getTotalCompensation().add(record.parallelStream().map(DailyVehicleOrderStatistics::getCompensation).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //加入违章
        vehicle.setTotalForfeit(vehicle.getTotalForfeit().add(record.parallelStream().map(DailyVehicleOrderStatistics::getForfeit).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //损坏赔偿
        vehicle.setTotalOrderCompensation(vehicle.getTotalOrderCompensation().add(record.parallelStream().map(DailyVehicleOrderStatistics::getOrderCompensation).reduce(BigDecimal.ZERO, BigDecimal::add)));
        return vehicle;
    }


    /**
     * 会员统计列表
     *
     * @param memberLevels
     * @param query
     * @return
     * @throws ParseException
     */
    public PageResult getMemberOrderStatistics(List<BaseUserMemberLevel> memberLevels, OrderQuery query) throws ParseException {

        List<MembersOrder> membersOrderList = membersBiz.getMemberOrderStatistics(query);

        //按每天分类
        if (CollectionUtil.isEmpty(membersOrderList)) {
            return PageResult.nowPageResult(query.getPage(), query.getLimit(), Lists.newArrayList());
        }
        //按每天分类
        if (CollectionUtil.isEmpty(memberLevels)) {
            throw new BaseException("获取不到会员信息");
        }
        //获取会员等级对应的名称
        HashMap<Integer, String> map = Maps.newHashMap();
        for (BaseUserMemberLevel memberLevel : memberLevels) {
            map.put(memberLevel.getLevel(), memberLevel.getName());
        }
        //按查询条件获取统计信息
        ArrayList<MembersOrderDto> arrayList = Lists.newArrayList();
        if (OrderInquiryType.DAY.getCode().equals(query.getType())) {
            for (MembersOrder mb : membersOrderList) {
                MembersOrderDto mbdto = new MembersOrderDto();
                //设置时间段
                mbdto.setTimeSlot(mb.getPeriod());
                TotalPaymentAndMemberName(map, mb, mbdto);
                arrayList.add(mbdto);
            }
        } else {
            for (int i = 0; i < membersOrderList.size(); i++) {
                MembersOrder mb = membersOrderList.get(i);
                String period = mb.getPeriod();
                if (StringUtils.isBlank(period)) {
                    continue;
                }
                MembersOrderDto mbdto = new MembersOrderDto();
                String[] periods = mb.getPeriod().split("-");
                String startDay = null;
                String endDay = null;
                Integer time = null;
                if (OrderInquiryType.WEEK.getCode().equals(query.getType())) {
                    startDay = OrderDateUtils.getStartDayOfWeekNo(Integer.parseInt(periods[0]), Integer.parseInt(periods[1]));
                    endDay = OrderDateUtils.getEndDayOfWeekNo(Integer.parseInt(periods[0]), Integer.parseInt(periods[1]));
                    //获取今天是今年的第几周
                    time = OrderDateUtils.getTodayOfWeek();
                }
                Integer thisYear = OrderDateUtils.getThisYear();
                if (OrderInquiryType.MONTH.getCode().equals(query.getType())) {
                    startDay = OrderDateUtils.getFirstDayOfMonth(Integer.parseInt(periods[0]), Integer.parseInt(periods[1]));
                    endDay = OrderDateUtils.getLastDayOfMonth(Integer.parseInt(periods[0]), Integer.parseInt(periods[1]));
                    //获取今天是今年的第几个月
                    time = OrderDateUtils.getTodayOfMonth();
                }

                if (i == 0 && query.getStartTime() != null) {
                    startDay = OrderDateUtils.timeStampConversionToString(query.getStartTime());
                }
                //获取当前的年.周(年.月)小数
                double today = Double.parseDouble(thisYear + "." + time);

                if (i == (membersOrderList.size() - 1)) {
                    //查询到的最后一条数据年.周(年.月)小数
                    double date = Double.parseDouble(Integer.parseInt(periods[0]) + "." + Integer.parseInt(periods[1]));
                    if (date == today) {
                        endDay = OrderDateUtils.timeStampConversionToString(System.currentTimeMillis());
                    } else if (date < today) {
                        //获取最后一条数据,周末日期
                        Long end = OrderDateUtils.ConvertingStringsToTimestamps(endDay);
                        //查询的结束日期
                        Long endTime = query.getEndTime();
                        if (endTime != null && end > endTime) {
                            endDay = OrderDateUtils.timeStampConversionToString(query.getEndTime());
                        }
                    }
                }
                if (StringUtils.isNotBlank(startDay) && StringUtils.isNotBlank(endDay)) {
                    mbdto.setTimeSlot(startDay + "~" + endDay);
                } else {
                    mbdto.setTimeSlot("");
                }
                TotalPaymentAndMemberName(map, mb, mbdto);
                arrayList.add(mbdto);
            }
        }

        //进行分页处理

        return PageResult.nowPageResult(query.getPage(), query.getLimit(), arrayList);
    }


    private void TotalPaymentAndMemberName(HashMap<Integer, String> map, MembersOrder mb, MembersOrderDto mbdto) {
        BigDecimal totalPayment = BigDecimal.ZERO;
        List<Member> members = mb.getMembers();
        //设置时间段购买会员总金额和不同的会员名称
        if (CollectionUtil.isNotEmpty(members)) {
            mbdto.setMembers(members);
            for (Member member : members) {
                member.setMemberName(map.get(member.getLevel()));
                totalPayment = totalPayment.add(member.getAmount() == null ? BigDecimal.ZERO : member.getAmount());
            }
        }
        mbdto.setTotalPayment(totalPayment);
    }


    public List<HashMap<Object, Object>> getRows(List<MembersOrderDto> list, List<BaseUserMemberLevel> memberLevels) {
        ArrayList<HashMap<Object, Object>> rows = Lists.newArrayList();
        for (MembersOrderDto membersOrderDto : list) {
            if (CollectionUtils.isEmpty(membersOrderDto.getMembers())) {
                continue;
            }
            HashMap<Object, Object> map = Maps.newLinkedHashMap();
            map.put("时间", membersOrderDto.getTimeSlot());
            for (BaseUserMemberLevel memberLevel : memberLevels) {
                setMap(membersOrderDto, map, memberLevel);
            }
            map.put("总支付金额", membersOrderDto.getTotalPayment());
            rows.add(map);
        }


        return rows;
    }

    private void setMap(MembersOrderDto membersOrderDto, HashMap<Object, Object> map, BaseUserMemberLevel memberLevel) {

        List<Member> collect = membersOrderDto.getMembers().parallelStream().filter(el -> el.getLevel().equals(memberLevel.getLevel())).collect(Collectors.toList());
        int number = 0;
        BigDecimal amount = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(collect)) {
            number = collect.get(0).getNumber();
            amount = collect.get(0).getAmount();
        }
        map.put(memberLevel.getName() + "购买量", number);
        map.put("支付金额(" + memberLevel.getName() + ")", amount);
    }

    @Cache(key = RedisKey.STATISTICS_ORDER_DAY+"{1}{2}")
    public BgStatisticsController.IndexOrderVO handleStatistics(String companyIds, String timeStr, List<String> vehicleIds) {
        //清空 RedisKey.STATISTICS_ORDER_DAY+"{1}"
        getMyBiz().getMyBiz().cacheClearStatistics(companyIds);

        BgStatisticsController.IndexOrderVO indexOrderVO = new BgStatisticsController.IndexOrderVO();
        OrderFullDTO orderFullDTO = new OrderFullDTO(){{
            setCrtTime(DateUtil.beginOfDay(DateUtil.date()));
            setHasPay(SYS_TRUE);
            setVehicleIds(vehicleIds);
            setMultiNotStatus(OrderStatusEnum.ORDER_CANCEL.getCode().toString());
        }};
        List<OrderFullVO> orderFullVOS = orderRentVehicleBiz.selectListFull(orderFullDTO);

        //今天订单金额
        BigDecimal allAmount = orderFullVOS.parallelStream().map(BaseOrder::getRealAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

        //今天订单数量
        Long allNum = Long.valueOf(orderFullVOS.size());

        //获取今天出发订单
        OrderFullDTO orderFullDTO2 = new OrderFullDTO(){{
            setStartTimeGte(DateUtil.beginOfDay(DateUtil.date()).getTime());
            setStartTimeLte(DateUtil.endOfDay(DateUtil.date()).getTime());
            setVehicleIds(vehicleIds);
            setMultiStatus(OrderStatusEnum.ORDER_TOSTART.getCode().toString());
        }};
        List<OrderFullVO> orderFullVOS2 = orderRentVehicleBiz.selectListFull(orderFullDTO2);
        //今天出发车辆数量
        Long toLiftNum = Long.valueOf(orderFullVOS2.size());

        //获取今天归还订单
        OrderFullDTO orderFullDTO3 = new OrderFullDTO(){{
            setEndTimeGte(DateUtil.beginOfDay(DateUtil.date()).getTime());
            setEndTimeLte(DateUtil.endOfDay(DateUtil.date()).getTime());
            setVehicleIds(vehicleIds);
            setMultiStatus(OrderStatusEnum.ORDER_WAIT.getCode().toString());
        }};
        List<OrderFullVO> orderFullVOS3 = orderRentVehicleBiz.selectListFull(orderFullDTO3);
        //今天归还车辆数量
        Long toReturnNum = Long.valueOf(orderFullVOS3.size());

        //获取今天归还订单
        OrderFullDTO orderFullDTO4 = new OrderFullDTO(){{
            setVehicleIds(vehicleIds);
            setMultiStatus(OrderStatusEnum.ORDER_FINISH.getCode().toString());
            setRefundStatus(RefundStatusEnum.RESIDUE_ILLEGAL.getCode());
        }};
        List<OrderFullVO> orderFullVOS4 = orderRentVehicleBiz.selectListFull(orderFullDTO4);
        //今天归还车辆数量
        Long toDealTrafficNum = Long.valueOf(orderFullVOS4.size());

        indexOrderVO.setCurrDayOrderAmount(allAmount);
        indexOrderVO.setCurrDayOrderNum(allNum);
        indexOrderVO.setCurrDayToLiftVehicleNum(toLiftNum);
        indexOrderVO.setCurrDayToReturnVehicleNum(toReturnNum);
        indexOrderVO.setToDealTrafficPay(toDealTrafficNum);
        return indexOrderVO;
    }

    @CacheClear(pre = RedisKey.STATISTICS_ORDER_DAY+"{1}")
    public void cacheClearStatistics(String companyIds) {;}

    private OrderStatisticsBiz getMyBiz() {
        return AopContext.currentProxy() != null ? (OrderStatisticsBiz) AopContext.currentProxy() : this;
    }

}
