content: package com.sky.service.impl;
  
  import com.alibaba.fastjson.JSON;
  import com.alibaba.fastjson.JSONArray;
  import com.alibaba.fastjson.JSONObject;
  import com.github.pagehelper.Constant;
  import com.github.pagehelper.Page;
  import com.github.pagehelper.PageHelper;
  import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
  import com.sky.constant.MessageConstant;
  import com.sky.context.BaseContext;
  import com.sky.dto.*;
  import com.sky.entity.*;
  import com.sky.exception.AddressBookBusinessException;
  import com.sky.exception.OrderBusinessException;
  import com.sky.exception.ShoppingCartBusinessException;
  import com.sky.mapper.*;
  import com.sky.result.PageResult;
  import com.sky.service.OrderService;
  import com.sky.utils.HttpClientUtil;
  import com.sky.utils.WeChatPayUtil;
  import com.sky.vo.OrderPaymentVO;
  import com.sky.vo.OrderStatisticsVO;
  import com.sky.vo.OrderSubmitVO;
  import com.sky.vo.OrderVO;
  import com.sky.websocket.WebSocketServer;
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.beans.BeanUtils;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  import java.math.BigDecimal;
  import java.time.LocalDateTime;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.stream.Collectors;
  
  /**
   * @version 1.0
   * @Author Imak
   * @Date 2024/8/12 15:07
   * @注释
   */
  @Service
  @Slf4j
  public class OrderServiceImpl implements OrderService {
      @Autowired
      private UserMapper userMapper;
      @Autowired
      private WeChatPayUtil weChatPayUtil;
      @Autowired
      private OrderMapper orderMapper;
      @Autowired
      private OrderDetailMapper orderDetailMapper;
      @Autowired
      private ShoppingCartMapper shoppingCartMapper;
      @Autowired
      private AddressBookMapper addressBookMapper;
      @Autowired
      private WebSocketServer webSocketServer;
  
      @Value("${sky.shop.address}")
      private String shopAddress;
  
      @Value("${sky.baidu.ak}")
      private String ak;
  
      /**
       * 检查客户的收货地址是否超出配送范围
       * @param address
       */
      private void checkOutOfRange(String address) {
          Map map = new HashMap();
          map.put("address",shopAddress);
          map.put("output","json");
          map.put("ak",ak);
  
          //获取店铺的经纬度坐标
          String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);
  
          JSONObject jsonObject = JSON.parseObject(shopCoordinate);
          if(!jsonObject.getString("status").equals("0")){
              throw new OrderBusinessException("店铺地址解析失败");
          }
  
          //数据解析
          JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
          String lat = location.getString("lat");
          String lng = location.getString("lng");
          //店铺经纬度坐标
          String shopLngLat = lat + "," + lng;
  
          map.put("address",address);
          //获取用户收货地址的经纬度坐标
          String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);
  
          jsonObject = JSON.parseObject(userCoordinate);
          if(!jsonObject.getString("status").equals("0")){
              throw new OrderBusinessException("收货地址解析失败");
          }
  
          //数据解析
          location = jsonObject.getJSONObject("result").getJSONObject("location");
          lat = location.getString("lat");
          lng = location.getString("lng");
          //用户收货地址经纬度坐标
          String userLngLat = lat + "," + lng;
  
          map.put("origin",shopLngLat);
          map.put("destination",userLngLat);
          map.put("steps_info","0");
  
          //路线规划
          String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);
  
          jsonObject = JSON.parseObject(json);
          if(!jsonObject.getString("status").equals("0")){
              throw new OrderBusinessException("配送路线规划失败");
          }
  
          //数据解析
          JSONObject result = jsonObject.getJSONObject("result");
          JSONArray jsonArray = (JSONArray) result.get("routes");
          Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");
  
          if(distance > 5000){
              //配送距离超过5000米
              throw new OrderBusinessException("超出配送范围");
          }
      }
      /**
       * 用户下单
       * @param ordersSubmitDTO
       * @return
       */
      @Transactional
      public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
          //异常情况的处理（收货地址为空、超出配送范围、购物车为空）
          AddressBook addressBook=addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
          if(addressBook==null){
              throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
          }
          //检查用户收货地址是否超出范围,先注释，因为没有作前端处理
         // checkOutOfRange(addressBook.getCityName()+addressBook.getDistrictName()+addressBook.getDetail());
  
          Long userId= BaseContext.getCurrentId();
          ShoppingCart shoppingCart=new ShoppingCart();
          shoppingCart.setUserId(userId);
  
          //查询购物车
          List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);
          if (shoppingCartList == null || shoppingCartList.size() == 0) {
              throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
          }
  
          //构造订单数据
          Orders orders=new Orders();
          BeanUtils.copyProperties(ordersSubmitDTO,orders);
          orders.setPhone(addressBook.getPhone());
          orders.setAddress(addressBook.getDetail());
          orders.setConsignee(addressBook.getConsignee());
  
          orders.setNumber(String.valueOf(System.currentTimeMillis()));
          orders.setUserId(userId);
          orders.setStatus(Orders.PENDING_PAYMENT);
          orders.setPayStatus(Orders.UN_PAID);
          orders.setOrderTime(LocalDateTime.now());
  
          //向订单表插入1条数据
          orderMapper.insert(orders);
  
          //订单明细数据
          List<OrderDetail> orderDetailList = new ArrayList<>();
          for (ShoppingCart cart : shoppingCartList) {
              OrderDetail orderDetail = new OrderDetail();
              BeanUtils.copyProperties(cart, orderDetail);
              orderDetail.setOrderId(orders.getId());
              orderDetailList.add(orderDetail);
          }
          //向明细表插入n条数据
          orderDetailMapper.insertBatch(orderDetailList);
  
          //清理购物车中的数据
          shoppingCartMapper.deleteByUserId(userId);
          //封装返回结果
          OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                  .id(orders.getId())
                  .orderNumber(orders.getNumber())
                  .orderAmount(orders.getAmount())
                  .orderTime(orders.getOrderTime())
                  .build();
  
          return orderSubmitVO;
  
      }
      /**
       * 订单支付
       * @param ordersPaymentDTO
       * @return
       */
      public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
          // 当前登录用户id
          //Long userId = BaseContext.getCurrentId();
          //User user = userMapper.getById(userId);
          // TODO 修改微信支付代码
  
          //调用微信支付接口，生成预支付交易单
  //        JSONObject jsonObject = weChatPayUtil.pay(
  //                ordersPaymentDTO.getOrderNumber(), //商户订单号
  //                new BigDecimal(0.01), //支付金额，单位 元
  //                "老卢外卖订单", //商品描述
  //                user.getOpenid() //微信用户的openid
  //        );
  //
  //        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
  //            throw new OrderBusinessException("该订单已支付");
  //        }
  //
  //        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
  //        vo.setPackageStr(jsonObject.getString("package"));
  
          paySuccess(ordersPaymentDTO.getOrderNumber());
  //      String orderNumber=ordersPaymentDTO.getOrderNumber();
  //      Long orderid=orderMapper.getOrderId(orderNumber);
          JSONObject jsonObject=new JSONObject();
          jsonObject.put("code","ORDERPAID");
          OrderPaymentVO vo=jsonObject.toJavaObject(OrderPaymentVO.class);
          vo.setPackageStr(jsonObject.getString("package"));
  //        Integer OrderPaidStatus=Orders.PAID;//已经支付
  //        Integer OrderStatus=Orders.TO_BE_CONFIRMED;
  //        LocalDateTime check_out_time=LocalDateTime.now();
  //        orderMapper.updateStatus(OrderStatus,OrderPaidStatus,check_out_time,orderid);
          return vo;
      }
      /**
       * 支付成功，修改订单状态
       * @param outTradeNo
       */
      public void paySuccess(String outTradeNo) {
          // 当前登录用户id
          Long userId = BaseContext.getCurrentId();
  
          // 根据订单号查询当前用户的订单
          Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);
  
          // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
          Orders orders = Orders.builder()
                  .id(ordersDB.getId())
                  .status(Orders.TO_BE_CONFIRMED)
                  .payStatus(Orders.PAID)
                  .checkoutTime(LocalDateTime.now())
                  .build();
  
          orderMapper.update(orders);
          Map map=new HashMap();
          map.put("type",1);
          map.put("orderId",orders.getId());
          map.put("content","订单号："+outTradeNo);
          //websocket向客户端推送信息
          webSocketServer.sendToAllClient(JSON.toJSONString(map));
      }
  
      /**
       * 订单分页查询
       * @param ordersPageQueryDTO
       * @return
       */
      public PageResult pageQuery(OrdersPageQueryDTO ordersPageQueryDTO) {
          //设置分页
          PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
          ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
  
          // TODO 安装mybatisx
          Page<Orders> page=orderMapper.pageQuery(ordersPageQueryDTO);
  
          List<OrderVO> list = new ArrayList<>();
          //查询订单明细
          if(page!=null&&page.getTotal()>0){
              for(Orders orders:page){
                  Long orderId=orders.getId();
                  List<OrderDetail> orderDetails=orderDetailMapper.getByOrderId(orderId);
                  OrderVO orderVO=new OrderVO();
                  BeanUtils.copyProperties(orders,orderVO);
                  orderVO.setOrderDetailList(orderDetails);
                  list.add(orderVO);
  
              }
          }
  
          return new PageResult(page.getTotal(), list);
  
  
      }
  
      /**
       * 根据订单id查询订单详细信息
       * @param id
       * @return
       */
      public OrderVO detail(Long id) {
          //根据id查询订单信息
          Orders orders = orderMapper.getById(id);
          List<OrderDetail> orderDetails=orderDetailMapper.getByOrderId(orders.getId());
          OrderVO orderVO=new OrderVO();
          BeanUtils.copyProperties(orders,orderVO);
          orderVO.setOrderDetailList(orderDetails);
          return orderVO;
      }
  
      /**
       * 再来一单
       * @param id
       */
      public void repetition(Long id) {
          // 查询当前用户id
          Long userId = BaseContext.getCurrentId();
  
          // 根据订单id查询当前订单详情
          List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
  
          // 将订单详情对象转换为购物车对象
          List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(x -> {
              ShoppingCart shoppingCart = new ShoppingCart();
  
              // 将原订单详情里面的菜品信息重新复制到购物车对象中
              BeanUtils.copyProperties(x, shoppingCart, "id");
              shoppingCart.setUserId(userId);
              shoppingCart.setCreateTime(LocalDateTime.now());
  
              return shoppingCart;
          }).collect(Collectors.toList());
  
          // 将购物车对象批量添加到数据库
          shoppingCartMapper.insertBatch(shoppingCartList);
  
      }
  
      /**
       * 取消订单
       * @param id
       */
      public void cancelOrder(Long id) {
  
          //查询订单，获取状态
          Orders orders=orderMapper.getById(id);
          // 校验订单是否存在
          if (orders == null) {
              throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
          }
          Integer status=orders.getStatus();
          //订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
          if (status > 2) {
              throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
          }
  
          Orders orderNew = new Orders();
          orderNew.setId(orders.getId());
  
          // 订单处于待接单状态下取消，需要进行退款
          if (orders.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
              //调用微信支付退款接口 跳过
  
              //支付状态修改为 退款
              orderNew.setPayStatus(Orders.REFUND);
          }
  
          // 更新订单状态、取消原因、取消时间
          orderNew.setStatus(Orders.CANCELLED);
          orderNew.setCancelReason("用户取消");
          orderNew.setCancelTime(LocalDateTime.now());
          orderMapper.update(orderNew);
      }
  
      /**
       * 订单条件查询
       * @param ordersPageQueryDTO
       * @return
       */
      public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
          PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
  
          Page<Orders> page = orderMapper.pageQuery(ordersPageQueryDTO);
  
          // 部分订单状态，需要额外返回订单菜品信息，将Orders转化为OrderVO
          List<OrderVO> orderVOList = getOrderVOList(page);
  
          return new PageResult(page.getTotal(), orderVOList);
      }
  
      /**
       * 各个状态订单统计
       * @return
       */
      public OrderStatisticsVO statistics() {
          // 根据状态，分别查询出待接单、待派送、派送中的订单数量
          Integer toBeConfirmed = orderMapper.countStatus(Orders.TO_BE_CONFIRMED);
          Integer confirmed = orderMapper.countStatus(Orders.CONFIRMED);
          Integer deliveryInProgress = orderMapper.countStatus(Orders.DELIVERY_IN_PROGRESS);
  
          OrderStatisticsVO orderStatisticsVO=new OrderStatisticsVO();
          orderStatisticsVO.setToBeConfirmed(toBeConfirmed);
          orderStatisticsVO.setConfirmed(confirmed);
          orderStatisticsVO.setDeliveryInProgress(deliveryInProgress);
          return orderStatisticsVO;
      }
  
      /**
       * 接单
       * @param ordersConfirmDTO
       */
      public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
          Orders orders = Orders.builder()
                  .id(ordersConfirmDTO.getId())
                  .status(Orders.CONFIRMED)
                  .build();
  
          orderMapper.update(orders);
      }
  
      /**
       * 拒单
       * @param ordersRejectionDTO
       */
      public void reject(OrdersRejectionDTO ordersRejectionDTO) {
          //封装实体
          Orders orders=orderMapper.getById(ordersRejectionDTO.getId());
          //只有待接单可以拒收
          if(orders.getStatus()!=Orders.TO_BE_CONFIRMED) {
              throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
          }
          //跳过订单支付状态查询和退款
          orders.setStatus(Orders.CANCELLED);
          orders.setCancelTime(LocalDateTime.now());
          orders.setRejectionReason(ordersRejectionDTO.getRejectionReason());
          orderMapper.update(orders);
  
      }
  
      private List<OrderVO> getOrderVOList(Page<Orders> page) {
          // 需要返回订单菜品信息，自定义OrderVO响应结果
          List<OrderVO> orderVOList = new ArrayList<>();
  
          List<Orders> ordersList = page.getResult();
          if (!CollectionUtils.isEmpty(ordersList)) {
              for (Orders orders : ordersList) {
                  // 将共同字段复制到OrderVO
                  OrderVO orderVO = new OrderVO();
                  BeanUtils.copyProperties(orders, orderVO);
                  String orderDishes = getOrderDishesStr(orders);
  
                  // 将订单菜品信息封装到orderVO中，并添加到orderVOList
                  orderVO.setOrderDishes(orderDishes);
                  orderVOList.add(orderVO);
              }
          }
          return orderVOList;
      }
      /**
       * 根据订单id获取菜品信息字符串
       * @param orders
       * @return
       */
      private String getOrderDishesStr(Orders orders) {
          // 查询订单菜品详情信息（订单中的菜品和数量）
          List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());
  
          // 将每一条订单菜品信息拼接为字符串（格式：宫保鸡丁*3；）
          List<String> orderDishList = orderDetailList.stream().map(x -> {
              String orderDish = x.getName() + "*" + x.getNumber() + ";";
              return orderDish;
          }).collect(Collectors.toList());
  
          // 将该订单对应的所有菜品信息拼接在一起
          return String.join("", orderDishList);
      }
      /**
       * 取消订单
       * @param ordersCancelDTO
       */
      public void cancel(OrdersCancelDTO ordersCancelDTO) throws Exception {
          // 根据id查询订单
          Orders ordersDB = orderMapper.getById(ordersCancelDTO.getId());
  
          //支付状态。跳过退款
          Integer payStatus = ordersDB.getPayStatus();
          if (payStatus == 1) {
              //用户已支付，需要退款
              log.info("申请退款：{}");
          }
  
          // 管理端取消订单需要退款，根据订单id更新订单状态、取消原因、取消时间
          Orders orders = new Orders();
          orders.setId(ordersCancelDTO.getId());
          orders.setStatus(Orders.CANCELLED);
          orders.setCancelReason(ordersCancelDTO.getCancelReason());
          orders.setCancelTime(LocalDateTime.now());
          orderMapper.update(orders);
      }
  
      /**
       * 派送订单
       * @param id
       */
      public void delivery(Long id) {
          //只有已经接单的可以派送
          //封装实体
          Orders orders=orderMapper.getById(id);
          //只有待接单可以拒收
          if(orders.getStatus()!=Orders.CONFIRMED) {
              throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
          }
          //跳过订单支付状态查询和退款
          orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
  
          orderMapper.update(orders);
      }
  
      /**
       * 完成订单
       * @param id
       */
      public void complete(Long id) {
          //只有已经派送中的的可以完成
          //封装实体
          Orders orders=orderMapper.getById(id);
          //只有待接单可以拒收
          if(orders.getStatus()!=Orders.DELIVERY_IN_PROGRESS) {
              throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
          }
          //跳过订单支付状态查询和退款
          orders.setStatus(Orders.COMPLETED);
          orders.setDeliveryTime(LocalDateTime.now());
  
          orderMapper.update(orders);
      }
  
      /**
       * 催单
       * @param id
       */
      public void reminder(Long id) {
  
          Orders orders=orderMapper.getById(id);
          if (orders == null) {
              throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
          }
          Long userId=orders.getUserId();
          Map map=new HashMap();
          map.put("type",2);
          map.put("orderId",id);
          map.put("content","用户"+userId+"催单啦");
          //websocket向客户端推送信息
          webSocketServer.sendToAllClient(JSON.toJSONString(map));
      }
  
  
  }
  