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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
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.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.carteenmoney.vo.*;
import cn.iocoder.yudao.module.member.dal.dataobject.carteenmoney.CarteenMoneyDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.orderdetail.OrderDetailDO;
import cn.iocoder.yudao.module.member.dal.mysql.carteenmoney.CarteenMoneyMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.orderdetail.OrderDetailMapper;
import cn.iocoder.yudao.module.member.enums.TimePeriodEnum;
import cn.iocoder.yudao.module.system.api.carteen.CarteenApi;
import cn.iocoder.yudao.module.system.api.carteen.dto.CarteenRespDto;
import cn.iocoder.yudao.module.system.api.deviceInfo.DeviceInfoApi;
import cn.iocoder.yudao.module.system.api.deviceInfo.dto.DeviceInfoDto;
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 门店流水 Service 实现类
 *
 * @author 开发账号
 */
@Service
@Validated
public class CarteenMoneyServiceImpl implements CarteenMoneyService {

    @Resource
    private CarteenMoneyMapper carteenMoneyMapper;
    @Resource
    private DishOrderMapper dishOrderMapper;
    @Resource
    private CarteenApi carteenApi;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private DeviceInfoApi deviceInfoApi;

    @Override
    public Long createCarteenMoney(CarteenMoneySaveReqVO createReqVO) {
        // 插入
        CarteenMoneyDO carteenMoney = BeanUtils.toBean(createReqVO, CarteenMoneyDO.class);
        carteenMoneyMapper.insert(carteenMoney);
        // 返回
        return carteenMoney.getId();
    }

    @Override
    public void updateCarteenMoney(CarteenMoneySaveReqVO updateReqVO) {
        // 校验存在
        validateCarteenMoneyExists(updateReqVO.getId());
        // 更新
        CarteenMoneyDO updateObj = BeanUtils.toBean(updateReqVO, CarteenMoneyDO.class);
        carteenMoneyMapper.updateById(updateObj);
    }

    @Override
    public void deleteCarteenMoney(Long id) {
        // 校验存在
        validateCarteenMoneyExists(id);
        // 删除
        carteenMoneyMapper.deleteById(id);
    }

    private void validateCarteenMoneyExists(Long id) {
        if (carteenMoneyMapper.selectById(id) == null) {
            throw exception(ErrorCodeConstants.CARTEEN_MONEY_NOT_EXISTS);
        }
    }

    @Override
    public CarteenMoneyDO getCarteenMoney(Long id) {
        return carteenMoneyMapper.selectById(id);
    }

    @Override
    public PageResult<CarteenMoneyDO> getCarteenMoneyPage(CarteenMoneyPageReqVO pageReqVO) {
       if(ObjUtil.isNotEmpty(pageReqVO.getCreateTime())){
           //开时间是否为今天
           if(LocalDateTimeUtil.isSameDay(pageReqVO.getCreateTime()[0].toLocalDate(),LocalDateTime.now().toLocalDate())){
               return  getCarteenMoneyDOPageResult(pageReqVO);
           }else{
               List<CarteenMoneyDO> todayCarteenMoney = this.getTodayCarteenMoney(pageReqVO.getCreateTime()[1],pageReqVO.getCarteenId());
               todayCarteenMoney.forEach(c -> c.setCreateTime(LocalDateTime.now()));
               PageResult<CarteenMoneyDO> page = carteenMoneyMapper.selectPage(pageReqVO);
               List<CarteenMoneyDO> list = page.getList();
               if(ObjUtil.isEmpty(list)){
                   list=new ArrayList<>();
               }
               list.addAll(todayCarteenMoney);
               list.sort(Comparator.comparing(CarteenMoneyDO::getCreateTime).reversed());
               page.setList(list);
               page.setTotal(page.getTotal()+ todayCarteenMoney.size());
               return page;
           }
       }else{
           LocalDateTime endDate = LocalDateTimeUtil.now();
           LocalDateTime startDate = LocalDateTimeUtil.beginOfDay(endDate);
           List<CarteenMoneyDO> dishOrderDO = this.getDishOrderDO(startDate, endDate, pageReqVO.getCarteenId());
           PageResult<CarteenMoneyDO> page=new PageResult<>();
           page.setList(dishOrderDO);
           page.setTotal((long) dishOrderDO.size());
           return page;
       }

    }
    @NotNull
    private PageResult<CarteenMoneyDO> getCarteenMoneyDOPageResult(CarteenMoneyPageReqVO pageReqVO) {
        List<CarteenMoneyDO> todayCarteenMoney = this.getTodayCarteenMoney(pageReqVO.getCreateTime()[1],pageReqVO.getCarteenId());
        PageResult<CarteenMoneyDO> page=new PageResult<>();
        page.setList(todayCarteenMoney);
        page.setTotal((long) todayCarteenMoney.size());
        return page;
    }




    /**
     * @Description: 获取今日门店流水
     * @Author: qjq
     * @Date: 2024/4/2 9:10
     * @return
     */
    public  List<CarteenMoneyDO> getTodayCarteenMoney(LocalDateTime endTime,Long storeId){
        //判断是否为同一天
        if(LocalDateTimeUtil.isSameDay(endTime,LocalDateTime.now())){
            //今日开始时间
            LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(endTime);
            //今日流水明细
            return this.getDishOrderDO(localDateTime, endTime,storeId);
        }
        return Collections.emptyList();
    }

    /**
     * @Description: 定时计算门店流水信息
     * @Author: qjq
     * @Date: 2024/4/1 17:38
     * @return
     */
    @Override
    public void  insertCarteenMoney(){
        //计算昨天的门店流水
        LocalDateTime now = LocalDateTimeUtil.now();
        //获取昨天
        LocalDateTime offset = LocalDateTimeUtil.offset(now, -1, ChronoUnit.DAYS);
        //昨天开始时间
        LocalDateTime startDate = LocalDateTimeUtil.beginOfDay(offset);
        //昨天结束时间
        LocalDateTime endDate = LocalDateTimeUtil.endOfDay(offset);
        carteenMoneyMapper.insertBatch(this.getDishOrderDO(startDate,endDate,null));
    }
    public List<CarteenMoneyDO> getDishOrderDO(LocalDateTime startDate, LocalDateTime endDate,Long storeId){
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(new LambdaQueryWrapperX<DishOrderDO>()
                .betweenIfPresent(DishOrderDO::getCreateTime, startDate, endDate)
                .eq(DishOrderDO::getOrderStatus, DishOrderDO.COMPLETE)
                .eqIfPresent(DishOrderDO::getStoreId,storeId));
        //根据门店id分组
        Map<Long, List<DishOrderDO>> collect = dishOrderDOS.stream().collect(Collectors.groupingBy(DishOrderDO::getStoreId));
        List<CarteenMoneyDO> list= new ArrayList<>();
        for (Map.Entry<Long, List<DishOrderDO>> longListEntry : collect.entrySet()) {
            //门店id
            Long storeId1 = longListEntry.getKey();
            List<DishOrderDO> value = longListEntry.getValue();
            //获取昨天门店的成交金额
            //double sum = value.stream().map(DishOrderDO::getTotalMoney).mapToDouble(BigDecimal::doubleValue).sum();
            BigDecimal bigDecimal1 = value.stream().map(DishOrderDO::getTotalMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //BigDecimal bigDecimal1 = BigDecimal.valueOf(sum);
            CarteenMoneyDO build = CarteenMoneyDO.builder()
                    .carteenName(value.get(0).getStoreName())
                    .carteenId(storeId1)
                    .successMoney(bigDecimal1)
                    .sumMoney(bigDecimal1)
                    .build();
            if(LocalDate.now().isEqual(endDate.toLocalDate())){
                build.setCreateTime( LocalDateTime.now());
            }else{
                build.setCreateTime( LocalDateTime.now().minusDays(1));
            }
            list.add(build);
        }
        return list;
    }

    /**
     * @param reqVO
     * @return
     * @Description: 获取门店下面的设备流水
     * @Author: qjq
     * @Date: 2024/4/12 下午3:13
     */
    @Override
    public DeviceMoneyRespVO getCarteenMoneyDevice(DeviceMoneyPageReqVO reqVO) {
        //时间为空默认为今天
        if(ObjUtil.isEmpty(reqVO.getCreateTime())){
            reqVO.setCreateTime(new LocalDateTime[]{LocalDateTimeUtil.beginOfDay(LocalDateTime.now()),LocalDateTimeUtil.endOfDay(LocalDateTime.now())});
        }
        //门店id
        Long carteenId = reqVO.getCarteenId();
        //获取门店信息
        CarteenRespDto car = carteenApi.getCarteenById(carteenId);
        DeviceMoneyRespVO bean = BeanUtil.toBean(car, DeviceMoneyRespVO.class);
        //获取门店下的设备
        List<String> ips = deviceInfoApi.getDeviceInfoList(bean.getId()).stream()
                .map(DeviceInfoDto::getDeviceIp)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        //获取设备营业数据
        List<OrderDetailDO> dos = orderDetailMapper.selectList(new LambdaQueryWrapperX<OrderDetailDO>()
                .in(OrderDetailDO::getSn, ips)
                .betweenIfPresent(OrderDetailDO::getCreateTime, reqVO.getCreateTime()));
        //根据设备分组
        Map<String, List<OrderDetailDO>> collect = dos.stream().collect(Collectors.groupingBy(OrderDetailDO::getSn));
        for (Map.Entry<String, List<OrderDetailDO>> map : collect.entrySet()) {
            List<OrderDetailDO> value = map.getValue();
            //根据时间进行时间段赋值
            value.forEach(v -> v.setCreator(TimePeriodEnum.getTimeName(v.getCreateTime())));
            //根据时间段分组
            value.stream().collect(Collectors.groupingBy(OrderDetailDO::getCreator))
                    .forEach((k, v) -> {
                        //设备流水
                        DeviceRespVO deviceRespVO = new DeviceRespVO();
                        //设置设备ip
                        deviceRespVO.setDeviceIp(map.getKey());
                        deviceRespVO.setDeviceName(deviceInfoApi.getDeviceInfoName(map.getKey()));
                        //根据时间段进行金额统计
                        BigDecimal sum = v.stream()
                                .map(OrderDetailDO::getPrice)
                                .filter(ObjectUtil::isNotEmpty)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                        deviceRespVO.setTime(k);
                        deviceRespVO.setMoney(sum);
                        bean.getDeviceRespVOList().add(deviceRespVO);
                    });

        }
        return bean;
    }
}