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

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
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.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.member.controller.admin.order.vo.OrderDetailsReqVO;
import cn.iocoder.yudao.module.member.controller.admin.order.vo.OrderDetailsRespVO;
import cn.iocoder.yudao.module.member.controller.admin.order.vo.OrderMoneyRespVO;
import cn.iocoder.yudao.module.member.controller.admin.screen.vo.CarTeenInfoVO;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppOrderPageReqVO;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppOrderRespVO;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppOrderSaveReqVO;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppPageVo;
import cn.iocoder.yudao.module.member.controller.app.orderdetail.vo.AppOrderDetailRespVO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.card.CardMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.enums.TimePeriodEnum;
import cn.iocoder.yudao.module.member.service.orderdetail.OrderDetailService;
import cn.iocoder.yudao.module.member.util.MemberConstants;
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 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.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.ORDER_NOT_EXISTS;

/**
 * 会员订单 Service 实现类
 *
 * @author 开发账号
 */
@Service
@Validated
public class OrderServiceImpl implements OrderService {

    @Resource
    private DishOrderMapper dishOrderMapper;

    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private DeviceInfoApi deviceInfoApi;
    @Resource
    private CarteenApi carteenApi;
    @Resource
    private CardMapper cardMapper;
    @Override
    public Long createOrder(AppOrderSaveReqVO createReqVO) {
        // 插入
        DishOrderDO order = BeanUtils.toBean(createReqVO, DishOrderDO.class);
        dishOrderMapper.insert(order);
        // 返回
        return order.getId();
    }

    @Override
    public void updateOrder(AppOrderSaveReqVO updateReqVO) {
        // 校验存在
        DishOrderDO dishOrderDO = dishOrderMapper.selectById(updateReqVO.getId());
        if (dishOrderDO == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
        //更新总价
        BigDecimal totalMoney = dishOrderDO.getTotalMoney().add(updateReqVO.getTotalMoney()).setScale(2, BigDecimal.ROUND_HALF_UP);
        updateReqVO.setTotalMoney(totalMoney);

        // 更新
        DishOrderDO updateObj = BeanUtils.toBean(updateReqVO, DishOrderDO.class);
        dishOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrder(Long id) {
        // 校验存在
        validateOrderExists(id);
        // 删除
        dishOrderMapper.deleteById(id);
    }

    private void validateOrderExists(Long id) {
        if (dishOrderMapper.selectById(id) == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
    }

    @Override
    public AppOrderRespVO getOrder(Long id) {
        DishOrderDO order = dishOrderMapper.selectById(id);
        AppOrderRespVO appOrderRespVO = BeanUtils.toBean(order, AppOrderRespVO.class);
        List<AppOrderDetailRespVO> appOrderDetailRespVOS = orderDetailService.selectListByOrderId(id);
        appOrderRespVO.setDetailList(appOrderDetailRespVOS);
        BigDecimal reduce1 = appOrderDetailRespVOS.stream().filter(heat -> ObjUtil.isNotEmpty(heat.getHeat())).map(m-> BigDecimal.valueOf(m.getHeat())).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal reduce = reduce1.setScale(2, RoundingMode.HALF_UP);
        appOrderRespVO.setIntake(reduce);
        //判断时间
        int hour = order.getCreateTime().getHour();
        if(TimePeriodEnum.MORNING.getStartInt()<=hour && hour<=TimePeriodEnum.MORNING.getEndInt()){
            appOrderRespVO.setProposeIntake(MemberConstants.PROPOSE_MORNING);
        } else if (TimePeriodEnum.MIDDAY.getStartInt()<=hour && hour<=TimePeriodEnum.MIDDAY.getEndInt()){
            appOrderRespVO.setProposeIntake(MemberConstants.PROPOSE_NOON);
        }else{
            appOrderRespVO.setProposeIntake(MemberConstants.PROPOSE_NIGHT);
        }
        appOrderRespVO.setDifference(NumberUtil.sub(reduce,appOrderRespVO.getProposeIntake()));
        return appOrderRespVO;
    }

    @Override
    public PageResult<DishOrderDO> getOrderPage(AppOrderPageReqVO pageReqVO) {
        return dishOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public  PageResult<AppOrderRespVO> getOrderList(AppPageVo vo) {
        PageResult<DishOrderDO> dishOrderDOPageResult = dishOrderMapper.selectPage(vo, Wrappers.<DishOrderDO>lambdaQuery().eq(DishOrderDO::getUserId, vo.getUserId()).orderByDesc(DishOrderDO::getCreateTime));
        PageResult<AppOrderRespVO> appOrderRespVOPageResult = BeanUtils.toBean(dishOrderDOPageResult, AppOrderRespVO.class);
        for (AppOrderRespVO dishOrderDO : appOrderRespVOPageResult.getList()){
            List<AppOrderDetailRespVO> appOrderDetailRespVOS = orderDetailService.selectListByOrderId(dishOrderDO.getId());
            dishOrderDO.setDetailList(appOrderDetailRespVOS);
        }

        return appOrderRespVOPageResult;
    }
    @Override
    public PageResult<OrderDetailsRespVO> getPageOrderDetails(OrderDetailsReqVO reqVO) {
        List<Long> userIds=new ArrayList<>();
        if(ObjUtil.isNotEmpty(reqVO.getUserName())
                || ObjUtil.isNotEmpty(reqVO.getUserAccount())
                || ObjUtil.isNotEmpty(reqVO.getUserJob())
                || ObjUtil.isNotEmpty(reqVO.getUserId())
        ){
            //根据用户属性获取ids
            userIds = memberUserMapper.selectList(new LambdaQueryWrapperX<MemberUserDO>()
                            .likeIfPresent(MemberUserDO::getNickname, reqVO.getUserName())
                            .eqIfPresent(MemberUserDO::getMobile, reqVO.getUserAccount())
                            .eqIfPresent(MemberUserDO::getCardId, reqVO.getUserJob())
                            .eqIfPresent(MemberUserDO::getId, reqVO.getUserId()))
                    .stream().map(MemberUserDO::getId).collect(Collectors.toList());
        }
        Map<String, LocalDateTime> timePeriod = this.getTimePeriod(reqVO.getTimePeriod());
        LocalDateTime startTime =null;
        LocalDateTime endTime =null;
        if(ObjUtil.isNotEmpty(timePeriod)){
            startTime=timePeriod.get("start");
            endTime=timePeriod.get("end");
        }
        //进行分页查询
        PageResult<DishOrderDO> pageResult = dishOrderMapper.selectPageList(reqVO, userIds, startTime, endTime);
        List<OrderDetailsRespVO> list=new ArrayList<>();
        for (DishOrderDO dishOrderDO : pageResult.getList()) {
            OrderDetailsRespVO bean = BeanUtils.toBean(dishOrderDO, OrderDetailsRespVO.class);
            userDetails(bean);
            list.add(bean);
        }
        return new PageResult<>(list,pageResult.getTotal());
    }

    @Override
    public OrderDetailsRespVO getOrderDetailsAndUser(Long orderId) {
        OrderDetailsRespVO bean = BeanUtils.toBean(dishOrderMapper.selectById(orderId), OrderDetailsRespVO.class);
        userDetails(bean);
        return bean;
    }

    private void userDetails(OrderDetailsRespVO bean) {
        MemberUserDO userDO = memberUserMapper.selectById(bean.getUserId());
        bean.setUserName(userDO.getNickname());
        bean.setUserJob(userDO.getMobile());
        bean.setAvatar(userDO.getAvatar());
        bean.setPayMethods("钱包");
        bean.setUserAccount(userDO.getMobile());
        bean.setTimePeriod(TimePeriodEnum.getTimeName(bean.getCreateTime()));
    }

    /**
     * @Description: 数据类型对标 {@link CostTypeEnum}
     * @Author: qjq
     * @Date: 2024/4/1 11:18
     * @return
     */
    public Map<String,LocalDateTime> getTimePeriod(String type){
        if(TimePeriodEnum.MORNING.getCode().equalsIgnoreCase(type)){
            return TimePeriodEnum.MORNING.getStartToEnd();
        }else if(TimePeriodEnum.MIDDAY.getCode().equalsIgnoreCase(type)){
            return TimePeriodEnum.MIDDAY.getStartToEnd();
        }else if(TimePeriodEnum.NIGHT.getCode().equalsIgnoreCase(type)){
            return TimePeriodEnum.NIGHT.getStartToEnd();
        }else {
            return Collections.emptyMap();
        }
    }

    @Override
    public List<DishOrderDO> getToPay(List<Long> users) {
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(Wrappers.<DishOrderDO>lambdaQuery()
                .in(DishOrderDO::getUserId, users)
                .eq(DishOrderDO::getOrderStatus, DishOrderDO.INCOMPLETE));
        return dishOrderDOS;
    }

    @Override
    public void updateBatch(List<DishOrderDO> orderDOS) {
        dishOrderMapper.updateBatch(orderDOS);
    }

    @Override
    public List<DishOrderDO> getDishOrderByTime(LocalDateTime startTime, LocalDateTime endTime) {
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(Wrappers.<DishOrderDO>lambdaQuery()
                .eq(DishOrderDO::getUserId,SecurityFrameworkUtils.getLoginUserId())
                .between(DishOrderDO::getCreateTime, startTime, endTime));
        return dishOrderDOS;
    }

    @Override
    public Integer selectUser(Long storeId, String time) {
        return dishOrderMapper.selectUser(storeId,time);
    }

    @Override
    public BigDecimal getSaleMoney(Long storeId, String time) {
        return dishOrderMapper.getSaleMoney(storeId,time);
    }

    @Override
    public List<CarTeenInfoVO> getCarTeenInfo() {
        List<CarTeenInfoVO> result = new ArrayList<>();
        List<CarteenRespDto> carteenList = carteenApi.getCarteenList();
        List<DeviceInfoDto> device = deviceInfoApi.getDevice();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(MemberConstants.DATE_FORMAT);
        String today = LocalDateTime.now().format(formatter);
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList();
        for (CarteenRespDto dto : carteenList){
            CarTeenInfoVO carTeenInfoVO = new CarTeenInfoVO();
            long deviceNum = device.stream().filter(vo -> vo.getCarteenId().equals(dto.getId())).count();
            carTeenInfoVO.setDeviceNum(String.valueOf(deviceNum));

            List<DishOrderDO> carteenOrderList = dishOrderDOS.stream().filter(dishOrderDO -> dishOrderDO.getStoreId().equals(dto.getId())).collect(Collectors.toList());
            BigDecimal totalMoney = carteenOrderList.stream().map(DishOrderDO::getTotalMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            carTeenInfoVO.setTodayMoney(totalMoney);

            List<DishOrderDO> todayCarteenOrderList = carteenOrderList.stream().filter(vo -> today.equals(vo.getCreateTime().format(formatter))).collect(Collectors.toList());
            BigDecimal todayMoney = todayCarteenOrderList.stream().map(DishOrderDO::getTotalMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            carTeenInfoVO.setTodayMoney(todayMoney);
            long peopleNUm = todayCarteenOrderList.stream().map(DishOrderDO::getUserId).distinct().count();
            carTeenInfoVO.setPeopleNUm(String.valueOf(peopleNUm));

            carTeenInfoVO.setStoresName(dto.getStoresName());
            carTeenInfoVO.setStoreId(dto.getId());

            result.add(carTeenInfoVO);
        }
        return result;
    }

    /**
     * @param userId
     * @return
     * @Description: 根据会员编号，获得会员余额,充值金额,消费金额
     * @Author: qjq
     * @Date: 2024/4/24 上午9:52
     */
    @Override
    public OrderMoneyRespVO getUserMeney(Long userId) {
        OrderMoneyRespVO orderMoneyRespVO = new OrderMoneyRespVO();
        //获取充值的金额
        BigDecimal add = cardMapper.selectAddMoney(userId, CardDO.ADD);

        orderMoneyRespVO.setRechargeMoney(add);
        //消费的金额
        BigDecimal minus = cardMapper.selectAddMoney(userId, CardDO.MINUS);
        orderMoneyRespVO.setConsumeMoney(minus);
        //获取会员余额
        BigDecimal subtract = add.subtract(minus);
        orderMoneyRespVO.setCurrentMoney(subtract);
        orderMoneyRespVO.setUserId(userId);
        return orderMoneyRespVO;
    }
}