package com.seer.teach.mall.order.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.seer.teach.common.enums.CommentStatusEnum;
import com.seer.teach.common.enums.OperateTypeEnum;
import com.seer.teach.common.enums.OrderStatusEnum;
import com.seer.teach.common.enums.PaymentModeEnum;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.ShippingStatusEnum;
import com.seer.teach.common.enums.UserTypeEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.BeanToMapConverter;
import com.seer.teach.mall.annotation.OrderLog;
import com.seer.teach.mall.convert.SenderConfigConvert;
import com.seer.teach.mall.entity.OrderChildEntity;
import com.seer.teach.mall.entity.OrderEntity;
import com.seer.teach.mall.entity.OrderGoodsEntity;
import com.seer.teach.mall.entity.SenderConfigEntity;
import com.seer.teach.mall.factory.LogisticsServiceFactory;
import com.seer.teach.mall.order.service.IAdminOrderService;
import com.seer.teach.mall.request.ChildOrderSenderReq;
import com.seer.teach.mall.request.OrderConsigneeUpdateReq;
import com.seer.teach.mall.request.OrderReq;
import com.seer.teach.mall.request.SenderConfigReq;
import com.seer.teach.mall.response.OrderResp;
import com.seer.teach.mall.service.IOrderChildService;
import com.seer.teach.mall.service.IOrderGoodsService;
import com.seer.teach.mall.service.IOrderQueryService;
import com.seer.teach.mall.service.IOrderService;
import com.seer.teach.mall.util.OrderLogUtils;
import com.seer.teach.mp.api.MpMessageServiceApi;
import com.seer.teach.mp.api.dto.MpSendMessageDTO;
import com.seer.teach.user.api.UserInfoServiceApi;
import com.seer.teach.user.api.dto.UserInfoDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * <p>
 * 后端管理用户订单服务实现类
 * </p>
 *
 * @author Captain
 * @since 2025-06-10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminOrderServiceImpl implements IAdminOrderService {

    private final IOrderService orderService;

    private final IOrderQueryService orderQueryService;

    private final IOrderChildService orderChildService;

    private final IOrderGoodsService orderGoodsService;

    private final LogisticsServiceFactory logisticsServiceFactory;

    private final MpMessageServiceApi mpMessageServiceApi;

    private final UserInfoServiceApi userInfoServiceApi;

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "管理员修改订单")
    public boolean updateOrder(OrderConsigneeUpdateReq orderUpdateReq) {
        Integer orderId = orderUpdateReq.getOrderId();
        log.info("开始更新订单，订单ID: {}", orderId);
        Integer userId = getUserId();
        OrderEntity queryOrder = orderService.getById(orderId);

        AssertUtils.notNull(queryOrder, ResultCodeEnum.ORDER_NOT_FOUND);

        orderService.updateOrderConsigneeInfo(orderUpdateReq);

        // 同步更新子订单信息
        List<OrderChildEntity> childrenOrders = orderChildService.getListByParentId(orderId);
        Set<Integer> childOrderIds = childrenOrders.stream().map(OrderChildEntity::getId).collect(Collectors.toSet());
        orderChildService.updateOrderConsigneeInfoByChildOrderIds(orderUpdateReq,childOrderIds);
        // 设置订单日志信息
        OrderLogUtils.setUpdateOrderInfo(userId,childrenOrders, queryOrder,UserTypeEnum.ADMIN);
        return true;
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "商家修改子订单")
    @Override
    public boolean updateChildOrder(OrderConsigneeUpdateReq orderUpdateReq, Long merchantUserId) {
        Integer userId = getUserId();
        log.info("开始更新子订单，子订单ID: {}", orderUpdateReq.getChildOrderId());

        // 检查子订单是否存在
        OrderChildEntity childOrder = orderChildService.checkOrderChild(orderUpdateReq.getChildOrderId());

        // 验证子订单是否属于该商家
        AssertUtils.isTrue(childOrder.getMerchantUserId().equals(merchantUserId), ResultCodeEnum.ORDER_NOT_FOUND);

        // 获取父订单信息
        OrderEntity order = orderService.checkOrderByOrderId(childOrder.getParentOrderId());

        // 更新子订单信息
        boolean result = orderChildService.updateOrderConsigneeInfo(orderUpdateReq);

        log.info("子订单更新结果：{}", result ? "成功" : "失败");

        // 设置订单日志信息
        OrderLogUtils.setUpdateOrderInfo(userId, Collections.singletonList(childOrder), order,UserTypeEnum.MERCHANT);
        return result;
    }

    @Override
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "管理员发货")
    public boolean deliveryOrder(Integer orderId, String logisticsCode, SenderConfigReq sender) {
        log.info("订单发货开始,订单Id{},物流公司编码{},寄件人信息：{}", orderId, logisticsCode, sender);

        OrderEntity order = orderService.getById(orderId);
        AssertUtils.notNull(order, ResultCodeEnum.ORDER_NOT_FOUND);
        log.info("订单信息：{}", order);
        AssertUtils.isTrue(order.getOrderStatus() == OrderStatusEnum.PAID.getCode(), ResultCodeEnum.ORDER_NOT_WAIT_SHIP);

        List<OrderGoodsEntity> goodsEntities = orderGoodsService.list(new LambdaQueryWrapper<OrderGoodsEntity>()
                .eq(OrderGoodsEntity::getOrderId, orderId));
        AssertUtils.notEmpty(goodsEntities, ResultCodeEnum.GOOD_NOT_FOUND);

        SenderConfigEntity senderConfigEntity = SenderConfigConvert.INSTANCE.req2entity(sender);

        Integer userId = getUserId();
        try {
            String billCode = logisticsServiceFactory.getService(logisticsCode).submitOrder(order, goodsEntities, senderConfigEntity);
            log.info("订单号：{}，物流单号：{}", orderId, billCode);

            // 更新订单的状态和物流单号
            boolean updateOrderStatusResult = orderService.deliveryOrder(orderId, logisticsCode, billCode, userId);
            // 同步更新子订单的状态和物流单号
            orderChildService.deliveryOrderByParentOrderId(orderId, logisticsCode, billCode, userId);
            // 设置订单日志信息
            OrderLogUtils.setUserInfo(userId, UserTypeEnum.ADMIN);
            OrderLogUtils.setDeliveryOrderInfo(orderId, null, getUserId(), ShippingStatusEnum.SHIPPED, CommentStatusEnum.NON_COMMENTED);
            return updateOrderStatusResult;
        } catch (Exception exception) {
            log.error("订单号：{}，异常：{}", orderId, exception.getMessage());
            OrderLogUtils.setUserInfo(userId, UserTypeEnum.ADMIN);
            OrderLogUtils.setDeliveryOrderExceptionInfo(orderId, null, getUserId(), exception.getMessage(), ShippingStatusEnum.SIGNED_EXCEPTION, CommentStatusEnum.NON_COMMENTED);
            return false;
        }
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "子订单发货")
    @Override
    public boolean deliveryChildOrder(Integer childOrderId, ChildOrderSenderReq childOrderSenderReq, Long merchantUserId) {
        log.info("子订单发货开始,子订单Id{},物流公司编码{},商家Id{}", childOrderId, childOrderSenderReq.getLogisticsCode(), merchantUserId);

        // 获取子订单信息
        OrderChildEntity childOrder = orderChildService.checkOrderChild(childOrderId);

        // 验证子订单是否属于该商家
        AssertUtils.isTrue(childOrder.getMerchantUserId().equals(merchantUserId), ResultCodeEnum.ORDER_NOT_FOUND);

        // 验证子订单状态是否为已支付
        AssertUtils.isTrue(childOrder.getOrderStatus() == OrderStatusEnum.PAID.getCode(), ResultCodeEnum.ORDER_NOT_WAIT_SHIP);

        Integer userId = getUserId();
        try {
            // 更新子订单的状态和物流信息
            boolean updateChildOrderStatusResult = orderChildService.deliveryOrder(childOrderId, childOrderSenderReq.getLogisticsCode(), childOrderSenderReq.getShippingNo(), userId);
            log.info("子订单号：{}，物流单号：{},更新子订单的状态和物流信息的结果:{}", childOrderId, childOrderSenderReq.getShippingNo(), updateChildOrderStatusResult);
            // 检查是否需要更新父订单状态
            List<OrderChildEntity> childOrders = orderChildService.getListByParentId(childOrder.getParentOrderId());

            // 如果所有子订单都已发货或已完成，则更新父订单状态为已发货
            boolean allChildShippedOrCompleted = childOrders.stream().filter(child -> child.getId().intValue() != childOrder.getId())
                    .allMatch(child -> child.getOrderStatus() == OrderStatusEnum.SHIPPED.getCode()
                            || child.getOrderStatus() == OrderStatusEnum.COMPLETED.getCode());

            if (allChildShippedOrCompleted) {
                log.info("父订单号：{}，所有子订单已发货或已完成，更新父订单状态为已发货", childOrder.getParentOrderId());
                boolean deliveryOrderResult = orderService.deliveryOrder(childOrder.getParentOrderId(), childOrderSenderReq.getLogisticsCode(), childOrderSenderReq.getShippingNo(), userId);
                log.info("父订单号：{}，更新父订单状态为已发货的结果:{}", childOrder.getParentOrderId(), deliveryOrderResult);
            }

            // 设置订单日志信息
            OrderLogUtils.setUserInfo(userId, UserTypeEnum.MERCHANT);
            OrderLogUtils.setDeliveryOrderInfo(childOrder.getParentOrderId(), childOrderId, userId, ShippingStatusEnum.SHIPPED, CommentStatusEnum.NON_COMMENTED);
            return updateChildOrderStatusResult;
        } catch (Exception exception) {
            log.error("子订单号：{}，异常：{}", childOrderId, exception.getMessage());
            OrderLogUtils.setUserInfo(userId, UserTypeEnum.MERCHANT);
            OrderLogUtils.setDeliveryOrderExceptionInfo(childOrder.getParentOrderId(), childOrderId, userId, exception.getMessage(), ShippingStatusEnum.SIGNED_EXCEPTION, CommentStatusEnum.NON_COMMENTED);
            return false;
        }
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    @OrderLog(operateType = OperateTypeEnum.DELETE, content = "管理员删除订单")
    public boolean deleteOrder(OrderReq orderReq) {
        Integer userId = getUserId();
        OrderEntity order = orderService.checkOrderByOrderId(orderReq.getId());
        AssertUtils.isTrue(OrderStatusEnum.DELETED.getCode() == order.getOrderStatus(), ResultCodeEnum.ORDER_NON_DELETE);
        List<OrderChildEntity> childOrders = orderChildService.getListByParentId(order.getId());
        orderService.removeById(order);
        boolean childRemoved = orderChildService.removeBatchByIds(childOrders);
        log.info("订单删除结果：{}", childRemoved ? "成功" : "失败");
        OrderLogUtils.setAdminDeleteOrderInfo(userId, childOrders,  order, UserTypeEnum.ADMIN);
        return childRemoved;
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    @OrderLog(operateType = OperateTypeEnum.DELETE, content = "商家删除订单")
    public boolean deleteChildOrder(OrderReq orderReq, Long merchantUserId) {
        Integer userId = getUserId();
        OrderChildEntity orderChildEntity = orderChildService.checkOrderChild(orderReq.getChildOrderId());
        OrderEntity order = orderService.checkOrderByOrderId(orderReq.getId());
        AssertUtils.isTrue(OrderStatusEnum.DELETED.getCode() == order.getOrderStatus(), ResultCodeEnum.ORDER_NON_DELETE);
        // 商家删除订单
        List<OrderChildEntity> childOrders = orderChildService.getListByParentId(order.getId());
        Optional<OrderChildEntity> any = childOrders.stream().filter(child -> child.getId() != orderChildEntity.getId()).findAny();
        if (!any.isPresent()) {
            // 删除父订单
            orderService.removeById(order);
        }
        OrderLogUtils.setUpdateOrderInfo(userId, childOrders,  order, UserTypeEnum.MERCHANT);
        return orderChildService.removeById(orderChildEntity);

    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    public boolean confirm(Integer orderId, Integer orderStatus, Integer deliveryUserId) {
        OrderEntity queryOrder = orderService.getById(orderId);
        AssertUtils.notNull(queryOrder, ResultCodeEnum.ORDER_NOT_FOUND);
        AssertUtils.isTrue(OrderStatusEnum.CONFIRMED.getCode() == orderStatus || orderStatus == OrderStatusEnum.REJECTED.getCode(), ResultCodeEnum.ORDER_NOT_OFFLINE_PAYMENT);
        AssertUtils.isTrue(queryOrder.getPaymentMode().intValue() == PaymentModeEnum.OFFLINE.getCode(), ResultCodeEnum.ORDER_NOT_OFFLINE_PAYMENT);
        if (queryOrder.getOrderStatus() == OrderStatusEnum.CONFIRMED.getCode() || queryOrder.getOrderStatus() == OrderStatusEnum.REJECTED.getCode()) {
            log.info("订单[{}]已确认，请勿重复操作", orderId);
            throw new CommonException(ResultCodeEnum.ORDER_CONFIRM_FAIL_STATUS_NOT_WAIT_CONFIRM);
        }
        boolean updateOrderStatusResult = orderService.update(new LambdaUpdateWrapper<OrderEntity>()
                .eq(OrderEntity::getId, orderId)
                .set(OrderEntity::getOrderStatus, orderStatus)
                .set(OrderEntity::getDeliveryTime, LocalDateTime.now())
                .set(OrderEntity::getDeliveryUserId, deliveryUserId));
        log.info("confirm 更新订单状态结果: {}", updateOrderStatusResult);
        if (updateOrderStatusResult) {
            orderChildService.update(new LambdaUpdateWrapper<>(OrderChildEntity.class)
                    .set(OrderChildEntity::getOrderStatus, orderStatus)
                    .eq(OrderChildEntity::getParentOrderId, orderId)
                    .set(OrderChildEntity::getDeliveryTime, LocalDateTime.now())
                    .set(OrderChildEntity::getDeliveryUserId, deliveryUserId));
        }
        // 订单确认成功，设置订单日志信息
        OrderLogUtils.setUserInfo(getUserId(), UserTypeEnum.ADMIN);
        OrderLogUtils.setConfirmOrderInfo(orderId, null, getUserId(), queryOrder.getOrderStatus(), orderStatus);
        return updateOrderStatusResult;
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    public boolean confirmAndNotify(Integer orderId, Integer orderStatus, Integer deliveryUserId, String businessSceneCode) {
        boolean confirm = confirm(orderId, orderStatus, deliveryUserId);
        if (confirm) {
            log.info("订单确认成功，开始发送消息");
            OrderResp order = orderQueryService.getOrderDetail(orderId);
            UserInfoDTO userInfoDTO = userInfoServiceApi.getById(order.getUserId());
            if (Objects.nonNull(userInfoDTO)) {
                order.setConsignee(getUserName(userInfoDTO));
            }
            Map<String, Object> data = BeanToMapConverter.toFlatMap(order);
            MpSendMessageDTO mpSendMessageDTO = new MpSendMessageDTO();
            mpSendMessageDTO.setBusinessId(orderId);
            mpSendMessageDTO.setData(data);
            mpSendMessageDTO.setBusinessSceneCode(businessSceneCode);
            log.info("发送模板消息开始");
            boolean sendMessageResult = mpMessageServiceApi.sendMessage(mpSendMessageDTO);
            log.info("发送模板消息结果: {}", sendMessageResult);
            return sendMessageResult;
        }
        return false;
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "管理员关闭订单")
    @Override
    public boolean closeOrder(OrderReq orderReq) {
        Integer userId = getUserId();
        OrderEntity order = orderService.checkOrderByOrderId(orderReq.getId());

        AssertUtils.isTrue(OrderStatusEnum.PENDING_PAYMENT.getCode() == order.getOrderStatus(), ResultCodeEnum.ORDER_NOT_WAIT_CLOSED_STATUS);

        boolean updateOrderStatusResult = orderService.update(new LambdaUpdateWrapper<OrderEntity>()
                .eq(OrderEntity::getId, orderReq.getId())
                .set(OrderEntity::getOrderStatus, OrderStatusEnum.CLOSED.getCode()));
        log.info("取消订单状态结果: {}", updateOrderStatusResult);
        AssertUtils.isTrue(updateOrderStatusResult, ResultCodeEnum.ORDER_CLOSE_FAIL);

        List<OrderChildEntity> childOrders = orderChildService.getListByParentId(order.getId());

        orderChildService.updateStatusByParentOrderId(order.getId(), OrderStatusEnum.CLOSED);

        OrderLogUtils.setAdminCloseOrderInfo(userId,order, childOrders);

        return true;
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @OrderLog(operateType = OperateTypeEnum.UPDATE, content = "商家关闭子订单")
    @Override
    public boolean closeChildOrder(OrderReq orderReq, Long merchantUserId) {
        OrderEntity queryOrder = orderService.getById(orderReq.getId());

        AssertUtils.notNull(queryOrder, ResultCodeEnum.ORDER_NOT_FOUND);
        AssertUtils.isTrue(OrderStatusEnum.PENDING_PAYMENT.getCode() == queryOrder.getOrderStatus(), ResultCodeEnum.ORDER_NOT_WAIT_CLOSED_STATUS);

        OrderChildEntity childOrder = orderChildService.checkOrderChild(orderReq.getChildOrderId());

        // 商家关闭订单
        List<OrderChildEntity> childOrders = orderChildService.getListByParentId(queryOrder.getId());
        boolean updateCurrentChildResult = orderChildService.update(new LambdaUpdateWrapper<OrderChildEntity>()
                .set(OrderChildEntity::getOrderStatus, OrderStatusEnum.CLOSED.getCode())
                .eq(OrderChildEntity::getId, orderReq.getChildOrderId())
                .eq(OrderChildEntity::getMerchantUserId, merchantUserId));

        log.info("子订单关闭结果：{}", updateCurrentChildResult ? "成功" : "失败");

        // 判断是否所有子订单都已关闭
        Optional<OrderChildEntity> any1 = childOrders.stream()
                .filter(co -> !co.getId().equals(orderReq.getChildOrderId()) && OrderStatusEnum.CLOSED.getCode() != co.getOrderStatus())
                .findAny();

        if (!any1.isPresent()) {
            updateParentOrderStatus(orderReq.getId(), OrderStatusEnum.CLOSED.getCode());
        }
        // 设置订单日志信息 - 商家关闭
        OrderLogUtils.setMerchantCloseOrderInfo(getUserId() ,merchantUserId,queryOrder, childOrder);
        return updateCurrentChildResult;

    }


    /**
     * 更新父订单状态
     *
     * @param orderId    订单ID
     * @param statusCode 状态码
     * @return 更新结果
     */
    private boolean updateParentOrderStatus(Integer orderId, int statusCode) {
        return orderService.update(new LambdaUpdateWrapper<OrderEntity>()
                .eq(OrderEntity::getId, orderId)
                .set(OrderEntity::getOrderStatus, statusCode));
    }


    private int getUserId() {
        return StpUtil.getLoginIdAsInt();
    }

    private String getUserName(UserInfoDTO userInfoDTO) {
        if (org.springframework.util.StringUtils.hasText(userInfoDTO.getRealName())) {
            return userInfoDTO.getRealName();
        }
        if (org.springframework.util.StringUtils.hasText(userInfoDTO.getNickName())) {
            return userInfoDTO.getNickName();
        }
        return userInfoDTO.getUserName();
    }
}