package cn.iocoder.yudao.module.member.service.storebusiness;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.controller.admin.business.vo.BusinessRespVO;
import cn.iocoder.yudao.module.member.controller.admin.business.vo.StatisticsVo;
import cn.iocoder.yudao.module.member.controller.admin.screen.vo.TurnoverVO;
import cn.iocoder.yudao.module.member.controller.admin.storebusiness.vo.StoreBusinessPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.storebusiness.vo.StoreBusinessSaveReqVO;
import cn.iocoder.yudao.module.member.controller.app.business.vo.BusinessDataVO;
import cn.iocoder.yudao.module.member.dal.dataobject.storebusiness.StoreBusinessDO;
import cn.iocoder.yudao.module.member.dal.mysql.storebusiness.StoreBusinessMapper;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.enums.TimePeriodEnum;
import cn.iocoder.yudao.module.member.util.MemberTimeUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.STORE_BUSINESS_NOT_EXISTS;

/**
 * 超市营业统计 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class StoreBusinessServiceImpl implements StoreBusinessService {

    @Resource
    private StoreBusinessMapper storeBusinessMapper;

    @Override
    public Long createStoreBusiness(StoreBusinessSaveReqVO createReqVO) {
        // 插入
        StoreBusinessDO storeBusiness = BeanUtils.toBean(createReqVO, StoreBusinessDO.class);
        storeBusinessMapper.insert(storeBusiness);
        // 返回
        return storeBusiness.getId();
    }

    @Override
    public void updateStoreBusiness(StoreBusinessSaveReqVO updateReqVO) {
        // 校验存在
        validateStoreBusinessExists(updateReqVO.getId());
        // 更新
        StoreBusinessDO updateObj = BeanUtils.toBean(updateReqVO, StoreBusinessDO.class);
        storeBusinessMapper.updateById(updateObj);
    }

    @Override
    public void deleteStoreBusiness(Long id) {
        // 校验存在
        validateStoreBusinessExists(id);
        // 删除
        storeBusinessMapper.deleteById(id);
    }

    private void validateStoreBusinessExists(Long id) {
        if (storeBusinessMapper.selectById(id) == null) {
            throw exception(STORE_BUSINESS_NOT_EXISTS);
        }
    }

    @Override
    public StoreBusinessDO getStoreBusiness(Long id) {
        return storeBusinessMapper.selectById(id);
    }

    @Override
    public PageResult<StoreBusinessDO> getStoreBusinessPage(StoreBusinessPageReqVO pageReqVO) {
        return storeBusinessMapper.selectPage(pageReqVO);
    }


    @Override
    public void updateStatistics(StatisticsVo vo) {
            LocalDate now = LocalDate.now();
            if(vo.getTime()!=null){
                now = vo.getTime().toLocalDate();
            }
            // 获取今天的开始时间
            LocalDateTime startOfDay =now.atStartOfDay();
            // 获取今天的结束时间 (23:59:59.999)
            LocalDateTime endOfDay = LocalDateTime.of(now, LocalTime.MAX);

            StoreBusinessDO storeBusinessDO = storeBusinessMapper.getTodayBusiness(vo.getCarteenId(), startOfDay, endOfDay);
            if (storeBusinessDO!=null) {

                //订单数
                storeBusinessDO.setOrderSum(storeBusinessDO.getOrderSum() + vo.getOrderSum());

                //营业额
                if(ObjectUtil.isNotEmpty(vo.getTotalMoney())){
                    storeBusinessDO.setTurnover(storeBusinessDO.getTurnover().add(vo.getTotalMoney()));
                }

                //客单价
                if(storeBusinessDO.getOrderSum() != 0){
                    storeBusinessDO.setPriceAvg(storeBusinessDO.getTurnover().divide(new BigDecimal(storeBusinessDO.getOrderSum()), 2, RoundingMode.HALF_UP));
                }else {
                    storeBusinessDO.setPriceAvg(BigDecimal.ZERO);
                }

                //减免金额
                if(ObjectUtil.isNotEmpty(vo.getReduceMoney())){
                    storeBusinessDO.setReduce(storeBusinessDO.getReduce().add(vo.getReduceMoney()));
                }

                //早中晚金额
                if(ObjectUtil.isNotEmpty(vo.getTime())){
                    String timePeriod = TimePeriodEnum.getTimePeriod(vo.getTime());

                    if(timePeriod.equals(CostTypeEnum.MORNING.getCode())){
                        storeBusinessDO.setBreakfast(storeBusinessDO.getBreakfast().add(vo.getTotalMoney()));
                        storeBusinessDO.setBreakfastNum(storeBusinessDO.getBreakfastNum() + vo.getOrderSum());
                    }else if (timePeriod.equals(CostTypeEnum.NOON.getCode())){
                        storeBusinessDO.setLunch(storeBusinessDO.getLunch().add(vo.getTotalMoney()));
                        storeBusinessDO.setLunchNum(storeBusinessDO.getLunchNum() + vo.getOrderSum());
                    }else if (timePeriod.equals(CostTypeEnum.NIGHT.getCode())){
                        storeBusinessDO.setDinner(storeBusinessDO.getDinner().add(vo.getTotalMoney()));
                        storeBusinessDO.setDinnerNum(storeBusinessDO.getDinnerNum() + vo.getOrderSum());
                    }
                }

                storeBusinessMapper.updateById(storeBusinessDO);
            }
        
    }


    @Override
    public BusinessDataVO getDay(String time, Long carteenId) {

        Integer nowDay = MemberTimeUtils.getDay(time);
        time = MemberTimeUtils.getYearMonth(time);

        BusinessDataVO businessDataVO = new BusinessDataVO();

        LambdaQueryWrapper<StoreBusinessDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreBusinessDO::getCarteenId,carteenId);
        wrapper.orderByAsc(StoreBusinessDO::getCreateTime);
        wrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", time);
        List<StoreBusinessDO> businessDOS = storeBusinessMapper.selectList(wrapper);

        Map<Integer, StoreBusinessDO> map = businessDOS.stream().collect(Collectors.toMap(
                vo -> vo.getCreateTime().toLocalDate().getDayOfMonth()
                , vo -> vo, (existing, replacement) -> existing));

        // 创建一个Map来存储每天的数据
        Map<Integer, BusinessRespVO> monthData = new LinkedHashMap<>();


        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

        // 将字符串解析为 YearMonth 对象
        YearMonth yearMonth = YearMonth.parse(time, formatter);

        // 获取当月的总天数
        int daysInMonth = yearMonth.lengthOfMonth();

        //获取上一个月最后一天的数据
        // 获取上一个月的最后一天
        YearMonth previousMonth = yearMonth.minusMonths(1);
        LocalDate lastDayOfPreviousMonth = previousMonth.atEndOfMonth();
        // 定义格式化器，将 LocalDate 转换为 yyyy-MM-dd 格式
        DateTimeFormatter formatterDay = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 将 LocalDate 转换为指定格式的字符串
        String formattedDate = lastDayOfPreviousMonth.format(formatterDay);


        LambdaQueryWrapper<StoreBusinessDO> previousWrapper = new LambdaQueryWrapper<>();
        previousWrapper.eq(StoreBusinessDO::getCarteenId,carteenId);
        previousWrapper.orderByAsc(StoreBusinessDO::getCreateTime);
        previousWrapper.apply("DATE_FORMAT(create_time, '%Y-%m-%d') = {0}", formattedDate);
        List<StoreBusinessDO> previousList = storeBusinessMapper.selectList(previousWrapper);
        BusinessRespVO old = new BusinessRespVO();
        if(CollectionUtil.isNotEmpty(previousList)){
            BeanUtil.copyProperties(previousList.get(0), old);
        }else {
            old = getInitBusinessRespVO();
        }

        // 循环遍历该月的每一天
        for (int day = 1; day <= daysInMonth; day++) {
            BusinessRespVO bean = new BusinessRespVO();
            if(map.get(day) == null){
                bean =  getInitBusinessRespVO().setTime(String.valueOf(day));
            }else {
                bean = BeanUtils.toBean(map.get(day), BusinessRespVO.class);
                bean.setTime(String.valueOf(day));
            }
            //计算差额
            if(day == 1){
                compare(bean,old);
            }else {
                compare(bean,monthData.get(day-1));
            }
            monthData.put(day,bean);

        }
        businessDataVO.setNow(monthData.get(nowDay));
        businessDataVO.setBusinessList(new ArrayList<>(monthData.values()));
        return businessDataVO;
    }



    @Override
    public BusinessDataVO getMonth(String time,Long carteenId) {
        time = MemberTimeUtils.getYearMonth(time);

        BusinessDataVO businessDataVO = new BusinessDataVO();

        int year = MemberTimeUtils.getYearFromYearMonthString(time);

        LambdaQueryWrapper<StoreBusinessDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreBusinessDO::getCarteenId,carteenId);
        wrapper.orderByAsc(StoreBusinessDO::getCreateTime);
        wrapper.apply("DATE_FORMAT(create_time, '%Y') = {0}", year);
        List<StoreBusinessDO> businessDOS = storeBusinessMapper.selectList(wrapper);

        Map<Integer,BusinessRespVO>  map = new HashMap<>();
        //时间处理
        for (int i = 1; i <= 12; i++) {
            BusinessRespVO bean = getInitBusinessRespVO();
            bean.setTime(String.valueOf(i));
            map.put(i,bean);
        }
        //数据统计
        for (StoreBusinessDO businessDO : businessDOS) {

            LocalDate date = businessDO.getCreateTime().toLocalDate();

            // 当前日期属于哪月
            int i = date.getMonthValue();
            BusinessRespVO businessRespVO = map.get(i);
            handleBusiness(businessDO,businessRespVO);
        }

        //上一年最后一月
        int previousYear = year - 1;
        LambdaQueryWrapper<StoreBusinessDO> previousWrapper = new LambdaQueryWrapper<>();
        previousWrapper.eq(StoreBusinessDO::getCarteenId,carteenId);
        previousWrapper.orderByAsc(StoreBusinessDO::getCreateTime);
        previousWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", previousYear+"-12");
        List<StoreBusinessDO> previousList = storeBusinessMapper.selectList(previousWrapper);
        BusinessRespVO previousVO = getInitBusinessRespVO();
        for (StoreBusinessDO businessDO : previousList) {
            handleBusiness(businessDO,previousVO);
        }
        //差额统计
        for (int i = 1; i <= 12; i++) {
            if(i == 1){
                compare(map.get(i),previousVO);
            }else {
                compare(map.get(i),map.get(i-1));
            }
        }

        int month = MemberTimeUtils.getMonthFromYearMonthString(time);
        businessDataVO.setNow(map.get(month));
        businessDataVO.setBusinessList(new ArrayList<>(map.values()));

        return businessDataVO;
    }


    void handleBusiness(StoreBusinessDO businessDO, BusinessRespVO businessRespVO) {
        //营业额
        businessRespVO.setTurnover(businessRespVO.getTurnover().add(businessDO.getTurnover()));
        //订单数
        businessRespVO.setOrderSum(businessRespVO.getOrderSum()+businessDO.getOrderSum());
        //均单价
        if(businessRespVO.getOrderSum()!=0){
            businessRespVO.setPriceAvg(businessRespVO.getTurnover().divide(new BigDecimal(businessRespVO.getOrderSum().toString()), 2, RoundingMode.HALF_UP));
        }
        //减免金额
        businessRespVO.setReduce(businessRespVO.getReduce().add(businessDO.getReduce()));
        //重量
        businessRespVO.setWeigh(businessRespVO.getWeigh().add(businessDO.getWeigh()));
        //早
        businessRespVO.setBreakfast(businessRespVO.getBreakfast().add(businessDO.getBreakfast()));
        //中
        businessRespVO.setLunch(businessRespVO.getLunch().add(businessDO.getLunch()));
        //晚
        businessRespVO.setDinner(businessRespVO.getDinner().add(businessDO.getDinner()));
        //门店
        businessRespVO.setCarteenId(businessDO.getCarteenId());
    }

    void compare(BusinessRespVO today, BusinessRespVO last) {
        today.setTurnoverCompare(today.getTurnover().subtract(last.getTurnover()));
        today.setOrderSumCompare(today.getOrderSum()-last.getOrderSum());
        today.setPriceAvgCompare(today.getPriceAvg().subtract(last.getPriceAvg()));
    }

    BusinessRespVO getInitBusinessRespVO() {
        BusinessRespVO previousVO = new BusinessRespVO();
        previousVO.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
                .setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO).setPriceAvg(BigDecimal.ZERO);
        return previousVO;
    }


    @Override
    public BusinessRespVO getTurnover(TurnoverVO turnoverVO) {

        List<StoreBusinessDO> businessDOS = storeBusinessMapper.selectList(Wrappers.<StoreBusinessDO>lambdaQuery()
                .between(StoreBusinessDO::getCreateTime,MemberTimeUtils.string2Time(turnoverVO.getStartTime()), MemberTimeUtils.string2Time(turnoverVO.getEndTime()))
                .eq(StoreBusinessDO::getCarteenId, turnoverVO.getStoreId()));
        BusinessRespVO businessDO = getInitBusinessRespVO();
        if(CollectionUtil.isNotEmpty(businessDOS)){
            businessDO.setTurnover(businessDOS.stream().map(StoreBusinessDO::getTurnover).reduce(BigDecimal.ZERO, BigDecimal::add));
            businessDO.setOrderSum(businessDOS.stream().map(StoreBusinessDO::getOrderSum).reduce(0, Integer::sum));
            businessDO.setCustomerSum(businessDOS.stream().map(StoreBusinessDO::getCustomerSum).reduce(0, Integer::sum));
            businessDO.setPriceAvg(businessDOS.stream().map(StoreBusinessDO::getPriceAvg).reduce(BigDecimal.ZERO, BigDecimal::add));
            businessDO.setBreakfast(businessDOS.stream().map(StoreBusinessDO::getBreakfast).reduce(BigDecimal.ZERO, BigDecimal::add));
            businessDO.setLunch(businessDOS.stream().map(StoreBusinessDO::getLunch).reduce(BigDecimal.ZERO, BigDecimal::add));
            businessDO.setDinner(businessDOS.stream().map(StoreBusinessDO::getDinner).reduce(BigDecimal.ZERO, BigDecimal::add));
            businessDO.setBreakfastNum(businessDOS.stream().map(StoreBusinessDO::getBreakfastNum).reduce(0, Integer::sum));
            businessDO.setLunchNum(businessDOS.stream().map(StoreBusinessDO::getLunchNum).reduce(0, Integer::sum));
            businessDO.setDinnerNum(businessDOS.stream().map(StoreBusinessDO::getDinnerNum).reduce(0, Integer::sum));
        }
        return businessDO;
    }

    @Override
    public List<BusinessRespVO> getTurnoverList(TurnoverVO turnoverVO) {
        LocalDateTime startTime = MemberTimeUtils.string2Time(turnoverVO.getStartTime());
        LocalDateTime endTime = MemberTimeUtils.string2Time(turnoverVO.getEndTime());

        LocalDate startDate = startTime.toLocalDate();
        LocalDate endDate = endTime.toLocalDate();
        if(startDate.equals(endDate)){
            // 获取本月开始时间：本月的第一天00:00:00
            startDate= startTime.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate();
            startTime = startDate.atStartOfDay();

            // 获取本月结束时间：本月的最后一天23:59:59.999999999
            endDate = endTime.with(TemporalAdjusters.lastDayOfMonth()).toLocalDate();
            endTime = endDate.atTime(LocalTime.MAX);
        }
        List<StoreBusinessDO> businessDOS = storeBusinessMapper.selectList(Wrappers.<StoreBusinessDO>lambdaQuery()
                .between(StoreBusinessDO::getCreateTime,startTime, endTime)
                .eq(StoreBusinessDO::getCarteenId, turnoverVO.getStoreId()));

        Map<LocalDateTime, StoreBusinessDO> map = businessDOS.stream()
                .filter(Objects::nonNull) // 过滤掉null值
                .collect(Collectors.toMap(
                        vo -> vo.getCreateTime().toLocalDate().atStartOfDay(),
                        vo -> vo,
                        (existing, replacement) -> existing
                ));

        // 生成从 startDate 到 endDate 的完整日期列表
        List<LocalDateTime> completeDates = new ArrayList<>();
        for (LocalDateTime date = startTime.toLocalDate().atStartOfDay(); !date.isAfter(endTime.toLocalDate().atStartOfDay()); date = date.plus(1, ChronoUnit.DAYS)) {
            completeDates.add(date);
        }
        // 遍历完整日期列表，补齐缺失的数据
        List<BusinessRespVO> completeRecords = new ArrayList<>();
        for (LocalDateTime date : completeDates) {
            BusinessRespVO bean;
            if(map.get(date) == null){
                bean =  getInitBusinessRespVO().setTime(MemberTimeUtils.Time2String(date));
            }else {
                bean = BeanUtils.toBean(map.get(date), BusinessRespVO.class);
                bean.setTime(MemberTimeUtils.Time2String(date));
            }
            completeRecords.add(bean);
        }

        return completeRecords;
    }


}