package com.ruoyi.web.modules.order.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.account.facade.IMemberFacade;
import com.ruoyi.web.modules.cart.facade.ICartFacade;
import com.ruoyi.web.modules.goods.mapper.BizGoodsMapper;
import com.ruoyi.web.modules.order.constant.CheckoutConstants;
import com.ruoyi.web.modules.order.constant.OrderAppConstants;
import com.ruoyi.web.modules.order.constant.OrderConstants;
import com.ruoyi.web.modules.order.domain.BizGoodsReview;
import com.ruoyi.web.modules.order.domain.BizOrder;
import com.ruoyi.web.modules.order.domain.BizOrderItem;
import com.ruoyi.web.modules.order.domain.BizOrderLogisticsTrace;
import com.ruoyi.web.modules.order.dto.OrderAppListQueryDTO;
import com.ruoyi.web.modules.order.dto.OrderAftersaleStatusRow;
import com.ruoyi.web.modules.order.mapper.BizGoodsReviewMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderAftersaleMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderItemMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderLogisticsTraceMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderMapper;
import com.ruoyi.web.modules.order.service.IOrderAppService;
import com.ruoyi.web.modules.order.service.IOrderCompletionService;
import com.ruoyi.web.modules.order.service.IOrderPaySuccessService;
import com.ruoyi.web.modules.order.support.CheckoutSupport;
import com.ruoyi.web.modules.order.support.OrderAppSupport;
import com.ruoyi.web.modules.order.vo.OrderAppBadgeVO;
import com.ruoyi.web.modules.order.vo.OrderAppDetailVO;
import com.ruoyi.web.modules.order.vo.OrderAppItemSummaryVO;
import com.ruoyi.web.modules.order.vo.OrderAppItemVO;
import com.ruoyi.web.modules.order.vo.OrderAppListRowVO;
import com.ruoyi.web.modules.pay.service.IWeChatPayService;
import com.ruoyi.web.modules.pay.vo.WeChatPayParamsVO;
import com.ruoyi.web.modules.store.domain.BizShop;
import com.ruoyi.web.modules.store.mapper.BizShopMapper;

/**
 * C 端订单 Service 实现
 */
@Service
public class OrderAppServiceImpl implements IOrderAppService
{
    @Autowired
    private IMemberFacade memberFacade;

    @Autowired
    private BizOrderMapper orderMapper;

    @Autowired
    private BizOrderItemMapper orderItemMapper;

    @Autowired
    private BizGoodsMapper goodsMapper;

    @Autowired
    private ICartFacade cartFacade;

    @Autowired
    private CheckoutSupport checkoutSupport;

    @Autowired
    private OrderAppSupport orderAppSupport;

    @Autowired
    private BizGoodsReviewMapper reviewMapper;

    @Autowired
    private BizOrderAftersaleMapper aftersaleMapper;

    @Autowired
    private BizOrderLogisticsTraceMapper traceMapper;

    @Autowired
    private BizShopMapper shopMapper;

    @Autowired
    private IWeChatPayService weChatPayService;

    @Autowired
    private IOrderPaySuccessService orderPaySuccessService;

    @Autowired
    private IOrderCompletionService orderCompletionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WeChatPayParamsVO createPay(Long memberId, Long orderId)
    {
        assertMemberEnabled(memberId);
        BizOrder order = requireOrder(memberId, orderId);
        String openid = memberFacade.getWxOpenid(memberId);
        WeChatPayParamsVO params = weChatPayService.createJsapiPay(memberId, order, openid);
        if (params.isMock())
        {
            orderPaySuccessService.completeWeChatPay(order.getOrderNo(), "MOCK" + order.getOrderNo(), new Date());
        }
        return params;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPay(Long memberId, Long orderId)
    {
        assertMemberEnabled(memberId);
        BizOrder order = requireOrder(memberId, orderId);
        checkoutSupport.assertPendingPay(order);
        int rows = orderMapper.updateForCancelPay(orderId, memberId, OrderConstants.CLOSE_TYPE_BUYER_CANCEL);
        if (rows == 0)
        {
            throw new ServiceException(OrderConstants.MSG_PENDING_PAY_ONLY);
        }
    }

    @Override
    public OrderAppBadgeVO getBadges(Long memberId)
    {
        assertMemberEnabled(memberId);
        OrderAppBadgeVO vo = new OrderAppBadgeVO();
        vo.setPendingPayCount(orderMapper.countMemberByStatus(memberId, OrderConstants.STATUS_PENDING_PAY));
        vo.setPendingShipCount(orderMapper.countMemberByStatus(memberId, OrderConstants.STATUS_PENDING_SHIP));
        vo.setPendingReceiveCount(orderMapper.countMemberByStatus(memberId, OrderConstants.STATUS_SHIPPED));
        vo.setAftersaleInProgressCount(aftersaleMapper.countInProgressByMember(memberId));
        return vo;
    }

    @Override
    public List<OrderAppListRowVO> list(Long memberId, OrderAppListQueryDTO query)
    {
        assertMemberEnabled(memberId);
        if (query == null)
        {
            query = new OrderAppListQueryDTO();
        }
        List<BizOrder> orders = orderMapper.selectMemberAppList(memberId, query);
        return buildListRows(orders);
    }

    @Override
    public OrderAppDetailVO getDetail(Long memberId, Long orderId)
    {
        assertMemberEnabled(memberId);
        BizOrder order = requireOrder(memberId, orderId);
        List<BizOrderItem> items = orderItemMapper.selectByOrderId(orderId);
        List<BizGoodsReview> reviews = reviewMapper.selectByOrderIds(Collections.singletonList(orderId));
        Map<Long, BizGoodsReview> reviewByItemId = orderAppSupport.indexReviewsByItemId(items, reviews);
        BizShop shop = order.getShopId() != null ? shopMapper.selectById(order.getShopId()) : null;
        BizOrderLogisticsTrace latestTrace = traceMapper.selectLatestByOrderId(orderId);

        OrderAppDetailVO vo = new OrderAppDetailVO();
        vo.setOrderId(order.getOrderId());
        vo.setOrderNo(order.getOrderNo());
        vo.setOrderStatus(order.getOrderStatus());
        vo.setOrderStatusText(orderAppSupport.toStatusText(order.getOrderStatus()));
        vo.setPayStatus(order.getPayStatus());
        vo.setPayType(order.getPayType());
        vo.setPayTypeText(orderAppSupport.toPayTypeText(order.getPayType()));
        vo.setGoodsAmount(order.getGoodsAmount());
        vo.setFreightAmount(order.getFreightAmount());
        vo.setPayAmount(order.getPayAmount());
        vo.setShopId(order.getShopId());
        vo.setShopName(order.getShopName());
        vo.setShopAvatar(shop != null ? shop.getShopAvatar() : null);
        vo.setConsigneeName(order.getConsigneeName());
        vo.setConsigneeMobile(order.getConsigneeMobile());
        vo.setConsigneeAddress(order.getConsigneeAddress());
        vo.setCreateTime(order.getCreateTime());
        vo.setPayTime(order.getPayTime());
        vo.setPayExpireTime(order.getPayExpireTime());
        vo.setPayRemainSeconds(orderAppSupport.calcPayRemainSeconds(order));
        vo.setFinishTime(order.getFinishTime());
        vo.setShipTime(order.getShipTime());
        vo.setCloseType(order.getCloseType());
        vo.setCloseTypeText(orderAppSupport.toCloseTypeText(order.getCloseType()));
        vo.setCloseReason(order.getCloseReason());
        vo.setDeliveryType(order.getDeliveryType());
        vo.setLogisticsCompany(order.getLogisticsCompany());
        vo.setTrackingNo(order.getTrackingNo());
        vo.setVehicleNo(order.getVehicleNo());
        vo.setCourierName(order.getCourierName());
        vo.setCourierMobile(order.getCourierMobile());
        vo.setLatestTrace(orderAppSupport.toLatestTrace(latestTrace));
        vo.setReviewStatus(orderAppSupport.resolveReviewStatus(order, items, reviewByItemId));
        vo.setActions(orderAppSupport.resolveActions(order));
        vo.setItems(toItemVos(items, order, reviewByItemId));
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReceive(Long memberId, Long orderId)
    {
        assertMemberEnabled(memberId);
        BizOrder order = requireOrder(memberId, orderId);
        Date now = new Date();
        orderCompletionService.completeOrder(order, now, String.valueOf(memberId), "买家确认收货");
    }

    private List<OrderAppListRowVO> buildListRows(List<BizOrder> orders)
    {
        if (orders == null || orders.isEmpty())
        {
            return Collections.emptyList();
        }
        List<Long> orderIds = orders.stream().map(BizOrder::getOrderId).collect(Collectors.toList());
        List<BizOrderItem> allItems = orderItemMapper.selectByOrderIds(orderIds);
        Map<Long, List<BizOrderItem>> itemMap = new HashMap<>();
        for (BizOrderItem item : allItems)
        {
            itemMap.computeIfAbsent(item.getOrderId(), k -> new ArrayList<>()).add(item);
        }
        List<BizGoodsReview> reviews = reviewMapper.selectByOrderIds(orderIds);
        Map<Long, String> shopAvatarMap = loadShopAvatars(orders);
        Map<Long, String> aftersaleStatusMap = loadAftersaleStatusMap(orderIds);
        List<OrderAppListRowVO> rows = new ArrayList<>(orders.size());
        for (BizOrder order : orders)
        {
            List<BizOrderItem> items = itemMap.getOrDefault(order.getOrderId(), Collections.emptyList());
            List<BizGoodsReview> orderReviews = reviews.stream()
                    .filter(review -> order.getOrderId().equals(review.getOrderId()))
                    .collect(Collectors.toList());
            Map<Long, BizGoodsReview> reviewByItemId = orderAppSupport.indexReviewsByItemId(items, orderReviews);
            OrderAppListRowVO row = new OrderAppListRowVO();
            row.setOrderId(order.getOrderId());
            row.setOrderNo(order.getOrderNo());
            row.setOrderStatus(order.getOrderStatus());
            row.setOrderStatusText(orderAppSupport.toStatusText(order.getOrderStatus()));
            row.setAftersaleStatus(aftersaleStatusMap.get(order.getOrderId()));
            row.setShopId(order.getShopId());
            row.setShopName(order.getShopName());
            row.setShopAvatar(shopAvatarMap.get(order.getShopId()));
            row.setPayAmount(order.getPayAmount());
            row.setGoodsAmount(order.getGoodsAmount());
            row.setFreightAmount(order.getFreightAmount());
            row.setCreateTime(order.getCreateTime());
            row.setItemCount(items.size());
            List<OrderAppItemSummaryVO> itemSummaries = new ArrayList<>(items.size());
            for (BizOrderItem item : items)
            {
                OrderAppItemSummaryVO summary = orderAppSupport.toItemSummary(item);
                orderAppSupport.enrichItemReview(summary, order, item, reviewByItemId);
                itemSummaries.add(summary);
            }
            row.setItems(itemSummaries);
            if (!itemSummaries.isEmpty())
            {
                row.setFirstItem(itemSummaries.get(0));
            }
            row.setPayRemainSeconds(orderAppSupport.calcPayRemainSeconds(order));
            row.setReviewStatus(orderAppSupport.resolveReviewStatus(order, items, reviewByItemId));
            row.setActions(orderAppSupport.resolveActions(order));
            rows.add(row);
        }
        return rows;
    }

    private Map<Long, String> loadAftersaleStatusMap(List<Long> orderIds)
    {
        if (orderIds == null || orderIds.isEmpty())
        {
            return Collections.emptyMap();
        }
        List<OrderAftersaleStatusRow> rows = aftersaleMapper.selectAftersaleStatusByOrderIds(orderIds);
        if (rows == null || rows.isEmpty())
        {
            return Collections.emptyMap();
        }
        Map<Long, String> map = new HashMap<>(rows.size());
        for (OrderAftersaleStatusRow row : rows)
        {
            if (row.getOrderId() != null)
            {
                map.put(row.getOrderId(), row.getAftersaleStatus());
            }
        }
        return map;
    }

    private Map<Long, String> loadShopAvatars(List<BizOrder> orders)
    {
        Map<Long, String> map = new HashMap<>();
        for (BizOrder order : orders)
        {
            if (order.getShopId() == null || map.containsKey(order.getShopId()))
            {
                continue;
            }
            BizShop shop = shopMapper.selectById(order.getShopId());
            map.put(order.getShopId(), shop != null ? shop.getShopAvatar() : null);
        }
        return map;
    }

    private List<OrderAppItemVO> toItemVos(List<BizOrderItem> items, BizOrder order,
            Map<Long, BizGoodsReview> reviewByItemId)
    {
        List<OrderAppItemVO> itemVos = new ArrayList<>();
        if (items == null)
        {
            return itemVos;
        }
        for (BizOrderItem item : items)
        {
            OrderAppItemVO itemVo = new OrderAppItemVO();
            itemVo.setItemId(item.getItemId());
            itemVo.setGoodsId(item.getGoodsId());
            itemVo.setGoodsName(item.getGoodsName());
            itemVo.setGoodsSpec(item.getGoodsSpec());
            itemVo.setGoodsImage(item.getGoodsImage());
            itemVo.setUnitPrice(item.getUnitPrice());
            itemVo.setQuantity(item.getQuantity());
            itemVo.setLineAmount(item.getLineAmount());
            itemVo.setBuyerRemark(item.getBuyerRemark());
            itemVo.setServiceDesc(item.getServiceDesc());
            if (order != null && OrderConstants.STATUS_COMPLETED.equals(order.getOrderStatus()))
            {
                BizGoodsReview review = reviewByItemId != null ? reviewByItemId.get(item.getItemId()) : null;
                if (review != null)
                {
                    itemVo.setReviewStatus(OrderAppConstants.REVIEW_STATUS_DONE);
                    itemVo.setReviewId(review.getReviewId());
                }
                else
                {
                    itemVo.setReviewStatus(OrderAppConstants.REVIEW_STATUS_PENDING);
                }
            }
            else
            {
                itemVo.setReviewStatus(OrderAppConstants.REVIEW_STATUS_NONE);
            }
            itemVos.add(itemVo);
        }
        return itemVos;
    }

    private BizOrder requireOrder(Long memberId, Long orderId)
    {
        BizOrder order = orderMapper.selectByIdAndMember(orderId, memberId);
        if (order == null)
        {
            throw new ServiceException(OrderConstants.MSG_NOT_FOUND);
        }
        return order;
    }

    private void assertMemberEnabled(Long memberId)
    {
        if (!memberFacade.isMemberEnabled(memberId))
        {
            throw new ServiceException(CheckoutConstants.MSG_MEMBER_DISABLED, 403);
        }
    }
}
