package cn.newfeifan.mall.module.trade.service.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.module.distri.mq.message.order.DistriOrderMessage;
import cn.newfeifan.mall.module.member.api.user.MemberUserApi;
import cn.newfeifan.mall.module.member.api.user.dto.MemberUserRespDTO;
import cn.newfeifan.mall.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO;
import cn.newfeifan.mall.module.product.api.sku.ProductSkuApi;
import cn.newfeifan.mall.module.system.dal.dataobject.user.AdminUserDO;
import cn.newfeifan.mall.module.system.dal.mysql.user.AdminUserMapper;
import cn.newfeifan.mall.module.trade.controller.admin.delivery.vo.expresstemplate.ShopBO;
import cn.newfeifan.mall.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
import cn.newfeifan.mall.module.trade.controller.admin.order.vo.TradeOrderSummaryRespVO;
import cn.newfeifan.mall.module.trade.controller.app.order.vo.AppTradeOrderDetailRespVO;
import cn.newfeifan.mall.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
import cn.newfeifan.mall.module.trade.convert.order.TradeOrderConvert;
import cn.newfeifan.mall.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.newfeifan.mall.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.newfeifan.mall.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.newfeifan.mall.module.trade.dal.redis.RedisKeyConstants;
import cn.newfeifan.mall.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.newfeifan.mall.module.trade.enums.order.TradeOrderStatusEnum;
import cn.newfeifan.mall.module.trade.framework.delivery.core.client.ExpressClientFactory;
import cn.newfeifan.mall.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO;
import cn.newfeifan.mall.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
import cn.newfeifan.mall.module.trade.framework.order.config.TradeOrderProperties;
import cn.newfeifan.mall.module.trade.service.delivery.DeliveryExpressService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.newfeifan.mall.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.EXPRESS_NOT_EXISTS;
import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;

/**
 * 交易订单【读】 Service 实现类
 *
 * @author 非繁源码
 */
@Service
@Slf4j
public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {

    @Resource
    private ExpressClientFactory expressClientFactory;

    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;

    @Resource
    private DeliveryExpressService deliveryExpressService;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private ProductSkuApi productSkuApi;
    @Resource
    private TradeOrderProperties tradeOrderProperties;


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AdminUserMapper userMapper;

    // =================== Order ===================

    @Override
    public TradeOrderDO getOrder(Long id) {
        return tradeOrderMapper.selectById(id);
    }

    @Override
    public TradeOrderDO getOrder(Long userId, Long id) {
        TradeOrderDO order = tradeOrderMapper.selectById(id);
        if (order != null
                && ObjectUtil.notEqual(order.getUserId(), userId)) {
            return null;
        }
        return order;
    }

    @Override
    public TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status) {
        return tradeOrderMapper.selectByUserIdAndCombinationActivityIdAndStatus(userId, combinationActivityId, status);
    }

    @Override
    public List<TradeOrderDO> getOrderList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return tradeOrderMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<TradeOrderDO> getOrderPage(TradeOrderPageReqVO reqVO) {
        // 根据用户查询条件构建用户编号列表
        Set<Long> userIds = buildQueryConditionUserIds(reqVO);
        if (userIds == null) { // 没查询到用户，说明肯定也没他的订单
            return PageResult.empty();
        }
        // 分页查询
        return tradeOrderMapper.selectPage(reqVO, userIds);
    }

    private Set<Long> buildQueryConditionUserIds(TradeOrderPageReqVO reqVO) {
        // 获得 userId 相关的查询
        Set<Long> userIds = new HashSet<>();
        if (StrUtil.isNotEmpty(reqVO.getUserMobile())) {
            MemberUserRespDTO user = memberUserApi.getUserByMobile(reqVO.getUserMobile());
            if (user == null) { // 没查询到用户，说明肯定也没他的订单
                return null;
            }
            userIds.add(user.getId());
        }
        if (StrUtil.isNotEmpty(reqVO.getUserNickname())) {
            List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(reqVO.getUserNickname());
            if (CollUtil.isEmpty(users)) { // 没查询到用户，说明肯定也没他的订单
                return null;
            }
            userIds.addAll(convertSet(users, MemberUserRespDTO::getId));
        }
        return userIds;
    }

    @Override
    public TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO) {
        // 根据用户查询条件构建用户编号列表
        Set<Long> userIds = buildQueryConditionUserIds(reqVO);
        if (userIds == null) { // 没查询到用户，说明肯定也没他的订单
            return new TradeOrderSummaryRespVO();
        }
        // 查询每个售后状态对应的数量、金额
        List<Map<String, Object>> list = tradeOrderMapper.selectOrderSummaryGroupByRefundStatus(reqVO, null);

        TradeOrderSummaryRespVO vo = new TradeOrderSummaryRespVO().setAfterSaleCount(0L).setAfterSalePrice(0L);
        for (Map<String, Object> map : list) {
            Long count = MapUtil.getLong(map, "count", 0L);
            Long price = MapUtil.getLong(map, "price", 0L);
            // 未退款的计入订单，部分退款、全部退款计入售后
            if (TradeOrderRefundStatusEnum.NONE.getStatus().equals(MapUtil.getInt(map, "refundStatus"))) {
                vo.setOrderCount(count).setOrderPayPrice(price);
            } else {
                vo.setAfterSaleCount(vo.getAfterSaleCount() + count).setAfterSalePrice(vo.getAfterSalePrice() + price);
            }
        }
        return vo;
    }

    @Override
    public PageResult<TradeOrderDO> getOrderPage(Long userId, AppTradeOrderPageReqVO reqVO) {
        return tradeOrderMapper.selectPage(reqVO, userId);
    }

    @Override
    public Long getOrderCount(Long userId, Integer status, Boolean commentStatus) {
        return tradeOrderMapper.selectCountByUserIdAndStatus(userId, status, commentStatus);
    }

    @Override
    public Long getOrderCount(Integer status) {
        return tradeOrderMapper.selectCountByStatus(status);
    }

    @Override
    public Long getOrderCount(Integer status, Long shopId, Long merId) {
        return tradeOrderMapper.selectCountByStatus(status, shopId, merId);
    }

    @Override
    public Long getOrderCount(Integer status, Long userId) {
        return tradeOrderMapper.selectCountByStatus(status, userId);
    }

    @Override
    public List<PayOrderPageItemRespVO> getOrderNoAndPicUrl(List<PayOrderPageItemRespVO> list) {
        for (PayOrderPageItemRespVO payOrderPageItemRespVO : list) {
            TradeOrderDO tradeOrderDO = tradeOrderMapper.selectById(payOrderPageItemRespVO.getId());
            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderId(payOrderPageItemRespVO.getId());
            if (tradeOrderDO != null && !tradeOrderItemDOS.isEmpty()) {
                payOrderPageItemRespVO.setPicUrl(tradeOrderItemDOS.get(0).getPicUrl());
                payOrderPageItemRespVO.setOrderNo(tradeOrderDO.getNo());
            }
        }
        return list;
    }

    @Override
    public Integer getShopSalesVolume(Long key) {

        return tradeOrderMapper.selectByMerId(key);

    }

    public List<TradeOrderDO> getTodayOrder() {
        // 获取7天之前的订单
        LocalDateTime start = LocalDateTime.now().minusDays(1).minusDays(7).with(LocalTime.of(3, 0, 0));
        LocalDateTime end = LocalDateTime.now().minusDays(7).with(LocalTime.of(2, 59, 59));

        return tradeOrderMapper.selectList(new LambdaQueryWrapper<TradeOrderDO>().between(TradeOrderDO::getCreateTime, start, end)
                .eq(TradeOrderDO::getStatus, 30).eq(TradeOrderDO::getPayStatus, true));
    }

    @Override
    public List<AppTradeOrderDetailRespVO> cancelOrderBySystem() {

        List<TradeOrderDO> order = getTodayOrder();
        if (order.isEmpty()) {
            return Collections.emptyList();
        }
        return order.stream().map(k -> {
            // 查询订单项
            List<TradeOrderItemDO> orderItems = getOrderItemListByOrderId(k.getId());
            // 查询物流公司
            DeliveryExpressDO express = k.getLogisticsId() != null && k.getLogisticsId() > 0 ?
                    deliveryExpressService.getDeliveryExpress(k.getLogisticsId()) : null;
            // 最终组合
            return TradeOrderConvert.INSTANCE.convert02(k, orderItems, tradeOrderProperties, express);
        }).collect(Collectors.toList());
    }

    @Override
    public List<DistriOrderMessage> queryAllOrder() {
        // 获取7天之前的订单
        LocalDateTime start = LocalDateTime.now().minusDays(1).minusDays(7).with(LocalTime.of(3, 0, 0));
        LocalDateTime end = LocalDateTime.now().minusDays(7).with(LocalTime.of(2, 59, 59));

        // 23年 - 24年
        // 获取当前日期
        LocalDate now = LocalDate.now();

        // 获取去年的第一天
        LocalDate firstDayLastYear = LocalDate.of(now.getYear() - 1, 1, 1);
        LocalDateTime firstDayLastYearStart = firstDayLastYear.atStartOfDay();

        // 获取今年的最后一天
        LocalDate lastDayThisYear = LocalDate.of(now.getYear(), 12, 31);
        LocalDateTime lastDayThisYearEnd = lastDayThisYear.atTime(23, 59, 59);


        return tradeOrderMapper.queryAllOrder(firstDayLastYearStart, lastDayThisYearEnd);

    }


    @Override
    public ShopBO getShop() {
        return getShopBO(stringRedisTemplate, userMapper, log);
    }

    public static ShopBO getShopBO(StringRedisTemplate stringRedisTemplate, AdminUserMapper userMapper, Logger log) {
        Long loginUserId = getLoginUserId();
        String s = stringRedisTemplate.opsForValue().get("shop:" + loginUserId);
        if (StringUtils.isEmpty(s)) {
            AdminUserDO adminUserDO = userMapper.selectById(loginUserId);
            ShopBO shop = new ShopBO();
            shop.setShopId(adminUserDO.getShopId());
            shop.setMerId(adminUserDO.getMerchantId());
            log.info("====shop:{}", shop);
            return shop;
        } else {
            log.info("====shop:{}", s);
            return JSONObject.parseObject(s, ShopBO.class);
        }
    }

    @Override
    public List<ExpressTrackRespDTO> getExpressTrackList(Long id, Long userId) {
        // 查询订单
        TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 查询物流
        return getExpressTrackList(order);
    }

    @Override
    public List<ExpressTrackRespDTO> getExpressTrackList(Long id) {
        // 查询订单
        TradeOrderDO order = tradeOrderMapper.selectById(id);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 查询物流
        return getExpressTrackList(order);
    }

    @Override
    public int getSeckillProductCount(Long userId, Long activityId) {
        // 获得订单列表
        List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId);
        orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单
        if (CollUtil.isEmpty(orders)) {
            return 0;
        }
        // 获得订单项列表
        return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId));
    }

    /**
     * 获得订单的物流轨迹
     *
     * @param order 订单
     * @return 物流轨迹
     */
    private List<ExpressTrackRespDTO> getExpressTrackList(TradeOrderDO order) {
        if (order.getLogisticsId() == null) {
            return Collections.emptyList();
        }
        // 查询物流公司
        DeliveryExpressDO express = deliveryExpressService.getDeliveryExpress(order.getLogisticsId());
        if (express == null) {
            throw exception(EXPRESS_NOT_EXISTS);
        }
        // 查询物流轨迹
        return getSelf().getExpressTrackList(express.getCode(), order.getLogisticsNo(), order.getReceiverMobile());
    }

    /**
     * 查询物流轨迹
     * <p>
     * 缓存的目的：考虑及时性要求不高，但是每次调用需要钱
     *
     * @param code           快递公司编码
     * @param logisticsNo    发货快递单号
     * @param receiverMobile 收、寄件人的电话号码
     * @return 物流轨迹
     */
    @Cacheable(cacheNames = RedisKeyConstants.EXPRESS_TRACK, key = "#code + '-' + #logisticsNo + '-' + #receiverMobile",
            condition = "#result != null")
    public List<ExpressTrackRespDTO> getExpressTrackList(String code, String logisticsNo, String receiverMobile) {
        return expressClientFactory.getDefaultExpressClient().getExpressTrackList(
                new ExpressTrackQueryReqDTO().setExpressCode(code).setLogisticsNo(logisticsNo)
                        .setPhone(receiverMobile));
    }


    // =================== Order Item ===================

    @Override
    public TradeOrderItemDO getOrderItem(Long userId, Long itemId) {
        TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId);
        if (orderItem != null
                && ObjectUtil.notEqual(orderItem.getUserId(), userId)) {
            return null;
        }
        return orderItem;
    }

    @Override
    public TradeOrderItemDO getOrderItem(Long id) {
        return tradeOrderItemMapper.selectById(id);
    }

    @Override
    public List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds) {
        if (CollUtil.isEmpty(orderIds)) {
            return Collections.emptyList();
        }

        return tradeOrderItemMapper.selectListByOrderId(orderIds);
    }


    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private TradeOrderQueryServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}
