package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.enums.RefundStatus;
import com.haha.common.constant.PaymentConstants;
import com.haha.entity.Order;
import com.haha.entity.OrderGoods;
import com.haha.entity.Refund;
import com.haha.entity.RefundItem;
import com.haha.mapper.RefundItemMapper;
import com.haha.mapper.RefundMapper;
import com.haha.service.OrderGoodsService;
import com.haha.service.OrderService;
import com.haha.service.RefundService;
import com.haha.service.payment.PaymentService;
import com.haha.service.payment.RefundResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
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.List;
import java.util.Map;

@Slf4j
@Service
public class RefundServiceImpl extends ServiceImpl<RefundMapper, Refund> implements RefundService {

    private final RefundItemMapper refundItemMapper;
    private final OrderService orderService;
    private final OrderGoodsService orderGoodsService;

    @Autowired
    @Lazy
    private PaymentService paymentService;

    @Autowired
    private com.haha.service.OrderInventoryService orderInventoryService;

    public RefundServiceImpl(RefundItemMapper refundItemMapper, OrderService orderService,
                             OrderGoodsService orderGoodsService) {
        this.refundItemMapper = refundItemMapper;
        this.orderService = orderService;
        this.orderGoodsService = orderGoodsService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Refund createRefundRecord(Long orderId, String reason, List<Map<String, Object>> products, BigDecimal refundAmount, Boolean restoreStock) {
        Order order = orderService.getById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 校验是否已有待审核的退款申请
        long pendingCount = lambdaQuery()
                .eq(Refund::getOrderId, orderId)
                .eq(Refund::getStatus, RefundStatus.PENDING.getCode())
                .count();
        if (pendingCount > 0) {
            throw new RuntimeException("该订单已有待审核的退款申请");
        }

        BigDecimal paidAmount = order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount();

        // 确定退款金额：products > refundAmount > 全额
        BigDecimal finalRefundAmount;
        if (products != null && !products.isEmpty()) {
            finalRefundAmount = calculateRefundAmount(products);
        } else if (refundAmount != null) {
            finalRefundAmount = refundAmount;
        } else {
            finalRefundAmount = paidAmount;
        }

        // 校验退款金额
        BigDecimal alreadyRefunded = getTotalRefundedAmount(orderId);
        BigDecimal availableAmount = paidAmount.subtract(alreadyRefunded);
        if (finalRefundAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("退款金额必须大于0");
        }
        if (finalRefundAmount.compareTo(availableAmount) > 0) {
            throw new RuntimeException("退款金额不能超过可退金额" + availableAmount + "元（实付" + paidAmount + "元，已退" + alreadyRefunded + "元）");
        }

        // 逐商品校验退款数量不超过剩余可退数量
        if (products != null && !products.isEmpty()) {
            Map<Long, Integer> refundedQuantityMap = getRefundedQuantityMap(orderId);
            for (Map<String, Object> p : products) {
                Long orderGoodsId = p.get("orderGoodsId") != null
                        ? Long.valueOf(p.get("orderGoodsId").toString()) : 0L;
                int requestQty = p.get("quantity") != null
                        ? Integer.parseInt(p.get("quantity").toString()) : 1;
                int alreadyRefundedQty = refundedQuantityMap.getOrDefault(orderGoodsId, 0);

                if (alreadyRefundedQty > 0 || refundedQuantityMap.containsKey(orderGoodsId)) {
                    // 查询原始购买数量
                    OrderGoods orderGoods = orderGoodsService.getById(orderGoodsId);
                    int originalQty = orderGoods != null && orderGoods.getProductNum() != null
                            ? orderGoods.getProductNum() : Integer.MAX_VALUE;
                    int remainingQty = originalQty - alreadyRefundedQty;

                    if (requestQty > remainingQty) {
                        String productName = (String) p.getOrDefault("productName", "商品");
                        throw new RuntimeException(productName + " 可退数量不足：已退" + alreadyRefundedQty
                                + "件，最多可退" + remainingQty + "件");
                    }
                }
            }
        }

        // 创建退款记录
        Refund refund = new Refund();
        refund.setOrderId(orderId);
        refund.setOrderNo(order.getOrderNo());
        refund.setRefundNo(generateRefundNo(order.getOrderNo()));
        refund.setRefundAmount(finalRefundAmount);
        refund.setTotalAmount(order.getTotalAmount());
        refund.setStatus(RefundStatus.PENDING.getCode());
        // 退款后是否恢复库存：默认为恢复（1），除非前端明确传 false
        refund.setRestoreStock(restoreStock == null || restoreStock ? 1 : 0);
        refund.setReason(reason);
        refund.setCreateTime(LocalDateTime.now());
        refund.setUpdateTime(LocalDateTime.now());
        this.save(refund);

        // 创建退款商品明细
        if (products != null && !products.isEmpty()) {
            List<RefundItem> items = new ArrayList<>();
            for (Map<String, Object> p : products) {
                RefundItem item = new RefundItem();
                item.setRefundId(refund.getId());
                item.setOrderGoodsId(p.get("orderGoodsId") != null
                        ? Long.valueOf(p.get("orderGoodsId").toString()) : 0L);
                item.setProductId(p.get("productId") != null
                        ? Long.valueOf(p.get("productId").toString()) : null);
                item.setProductName((String) p.getOrDefault("productName", ""));
                item.setPic((String) p.getOrDefault("pic", null));
                item.setQuantity(p.get("quantity") != null
                        ? Integer.valueOf(p.get("quantity").toString()) : 1);
                item.setPrice(p.get("price") != null
                        ? new BigDecimal(p.get("price").toString()) : BigDecimal.ZERO);
                item.setRefundAmount(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
                item.setCreateTime(LocalDateTime.now());
                items.add(item);
            }
            for (RefundItem item : items) {
                refundItemMapper.insert(item);
            }
        }

        // 更新订单关联（不设置 refundAmount，由 updateOrderRefundStatus 计算累计值）
        order.setCurrentRefundId(refund.getId());
        order.setRefundStatus(RefundStatus.PENDING.getCode());
        order.setRefundReason(reason);
        orderService.updateById(order);

        log.info("退款记录创建成功 - refundId: {}, orderId: {}, amount: {}", refund.getId(), orderId, finalRefundAmount);
        return refund;
    }

    @Override
    public Refund createRefundRecord(Map<String, Object> params) {
        Long orderId = Long.valueOf(params.get("orderId").toString());
        String reason = params.containsKey("reason") ? params.get("reason").toString() : "用户申请退款";

        @SuppressWarnings("unchecked")
        List<Map<String, Object>> products = (List<Map<String, Object>>) params.get("products");

        BigDecimal refundAmount = null;
        if (params.containsKey("refundAmount") && params.get("refundAmount") != null) {
            refundAmount = new BigDecimal(params.get("refundAmount").toString());
        }

        Boolean restoreStock = null;
        if (params.containsKey("restoreStock") && params.get("restoreStock") != null) {
            Object val = params.get("restoreStock");
            restoreStock = val instanceof Boolean ? (Boolean) val : Boolean.parseBoolean(val.toString());
        }

        return createRefundRecord(orderId, reason, products, refundAmount, restoreStock);
    }

    @Override
    public Refund getDetailById(Long refundId) {
        return this.getById(refundId);
    }

    @Override
    public Map<Long, Integer> getRefundedQuantityMap(Long orderId) {
        Map<Long, Integer> result = new java.util.HashMap<>();
        // 查询该订单所有已退款成功的记录
        List<Refund> refundedList = lambdaQuery()
                .eq(Refund::getOrderId, orderId)
                .eq(Refund::getStatus, RefundStatus.REFUNDED.getCode())
                .list();
        if (refundedList == null || refundedList.isEmpty()) {
            return result;
        }
        for (Refund refund : refundedList) {
            List<RefundItem> items = getRefundItems(refund.getId());
            if (items != null) {
                for (RefundItem item : items) {
                    result.merge(item.getOrderGoodsId(), item.getQuantity(), Integer::sum);
                }
            }
        }
        return result;
    }

    @Override
    public Map<Long, Map<Long, Integer>> getRefundedQuantityMapByOrderIds(List<Long> orderIds) {
        Map<Long, Map<Long, Integer>> result = new java.util.HashMap<>();
        if (orderIds == null || orderIds.isEmpty()) {
            return result;
        }
        // 一次性查所有退款记录
        List<Refund> refundedList = lambdaQuery()
                .in(Refund::getOrderId, orderIds)
                .eq(Refund::getStatus, RefundStatus.REFUNDED.getCode())
                .list();
        if (refundedList == null || refundedList.isEmpty()) {
            return result;
        }
        // 收集所有 refundId 批量查退款明细
        List<Long> refundIds = refundedList.stream().map(Refund::getId).collect(java.util.stream.Collectors.toList());
        List<RefundItem> allItems = refundItemMapper.selectList(
                new LambdaQueryWrapper<RefundItem>().in(RefundItem::getRefundId, refundIds));
        if (allItems == null || allItems.isEmpty()) {
            return result;
        }
        // 建立 refundId → orderId 映射
        Map<Long, Long> refundToOrder = refundedList.stream()
                .collect(java.util.stream.Collectors.toMap(Refund::getId, Refund::getOrderId));
        // 按 orderId 聚合
        for (RefundItem item : allItems) {
            Long orderId = refundToOrder.get(item.getRefundId());
            if (orderId != null) {
                result.computeIfAbsent(orderId, k -> new java.util.HashMap<>())
                        .merge(item.getOrderGoodsId(), item.getQuantity(), Integer::sum);
            }
        }
        return result;
    }

    @Override
    public List<Refund> getByOrderId(Long orderId) {
        return lambdaQuery()
                .eq(Refund::getOrderId, orderId)
                .orderByDesc(Refund::getCreateTime)
                .list();
    }

    @Override
    public IPage<Refund> getRefundPage(int page, int pageSize, String orderNo,
                                        String status, String startDate, String endDate) {
        LambdaQueryWrapper<Refund> wrapper = new LambdaQueryWrapper<Refund>()
                .eq(orderNo != null && !orderNo.isEmpty(), Refund::getOrderNo, orderNo)
                .eq(status != null && !status.isEmpty(), Refund::getStatus, status)
                .ge(startDate != null && !startDate.isEmpty(), Refund::getCreateTime, startDate)
                .le(endDate != null && !endDate.isEmpty(), Refund::getCreateTime, endDate + " 23:59:59")
                .orderByDesc(Refund::getCreateTime);
        return this.page(new Page<>(page, pageSize), wrapper);
    }

    @Override
    public List<RefundItem> getRefundItems(Long refundId) {
        return refundItemMapper.selectList(
                new LambdaQueryWrapper<RefundItem>()
                        .eq(RefundItem::getRefundId, refundId));
    }

    @Override
    public BigDecimal getTotalRefundedAmount(Long orderId) {
        List<Refund> refunds = lambdaQuery()
                .eq(Refund::getOrderId, orderId)
                .eq(Refund::getStatus, RefundStatus.REFUNDED.getCode())
                .list();
        BigDecimal total = BigDecimal.ZERO;
        for (Refund r : refunds) {
            if (r.getRefundAmount() != null) {
                total = total.add(r.getRefundAmount());
            }
        }
        return total;
    }

    @Override
    public BigDecimal calculateRefundAmount(List<Map<String, Object>> products) {
        if (products == null || products.isEmpty()) {
            return BigDecimal.ZERO;
        }
        BigDecimal total = BigDecimal.ZERO;
        for (Map<String, Object> p : products) {
            BigDecimal price = p.get("price") != null
                    ? new BigDecimal(p.get("price").toString()) : BigDecimal.ZERO;
            int quantity = p.get("quantity") != null
                    ? Integer.parseInt(p.get("quantity").toString()) : 1;
            total = total.add(price.multiply(BigDecimal.valueOf(quantity)));
        }
        return total;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean approveRefund(Long refundId, String remark, Long reviewerId) {
        Refund refund = this.getById(refundId);
        if (refund == null || !refund.isPending()) {
            log.warn("退款记录不存在或状态不是待审核 - refundId: {}, status: {}",
                    refundId, refund != null ? refund.getStatus() : "null");
            return false;
        }

        // 执行第三方退款
        RefundResult result = paymentService.refund(refund.getOrderId(), refund.getReason(), refund.getRefundAmount());

        if (result.isSuccess()) {
            // 直接更新当前对象，不要调用 markRefunded（会加载另一个实例覆盖）
            refund.setStatus(RefundStatus.REFUNDED.getCode());
            refund.setTransactionId(result.getRefundId());
            refund.setRefundTime(LocalDateTime.now());
            refund.setRemark(remark);
            refund.setReviewerId(reviewerId);
            refund.setReviewTime(LocalDateTime.now());
            refund.setUpdateTime(LocalDateTime.now());
            this.updateById(refund);

            // 退款成功后恢复库存
            restoreStockForRefund(refund);

            log.info("退款审核通过并执行成功 - refundId: {}, transactionId: {}", refundId, result.getRefundId());
            return true;
        } else {
            log.error("退款执行失败 - refundId: {}, error: {}", refundId, result.getErrorMsg());
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rejectRefund(Long refundId, String remark, Long reviewerId) {
        Refund refund = this.getById(refundId);
        if (refund == null || !refund.isPending()) {
            return false;
        }

        refund.setStatus(RefundStatus.REJECTED.getCode());
        refund.setRemark(remark);
        refund.setReviewerId(reviewerId);
        refund.setReviewTime(LocalDateTime.now());
        refund.setUpdateTime(LocalDateTime.now());
        this.updateById(refund);

        // 清除订单退款状态（用 LambdaUpdateWrapper 显式设 null，MyBatis-Plus 默认忽略 null 字段）
        orderService.lambdaUpdate()
                .set(Order::getRefundStatus, null)
                .set(Order::getCurrentRefundId, null)
                .set(Order::getRefundReason, null)
                .eq(Order::getId, refund.getOrderId())
                .update();

        log.info("退款申请已拒绝 - refundId: {}", refundId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markRefunded(Long refundId, String transactionId) {
        Refund refund = this.getById(refundId);
        if (refund != null) {
            refund.setStatus(RefundStatus.REFUNDED.getCode());
            refund.setTransactionId(transactionId);
            refund.setRefundTime(LocalDateTime.now());
            refund.setUpdateTime(LocalDateTime.now());
            this.updateById(refund);

            // 退款成功后恢复库存
            restoreStockForRefund(refund);
        }
    }

    /**
     * 退款成功后恢复对应商品的库存
     * 仅当 restoreStock=1 时执行（质量问题等不需要退库存的场景跳过）
     */
    private void restoreStockForRefund(Refund refund) {
        // restoreStock 默认为 1（恢复），仅当明确为 0 时跳过
        if (refund.getRestoreStock() != null && refund.getRestoreStock() == 0) {
            log.info("退款标记为不恢复库存，跳过: refundId={}, orderId={}", refund.getId(), refund.getOrderId());
            return;
        }
        try {
            Order order = orderService.getById(refund.getOrderId());
            if (order == null) {
                log.warn("订单不存在，跳过库存恢复: orderId={}", refund.getOrderId());
                return;
            }
            List<RefundItem> refundItems = getRefundItems(refund.getId());
            orderInventoryService.restoreStockOnRefund(order, refundItems);
        } catch (Exception e) {
            log.error("退款恢复库存异常: refundId={}, orderId={}", refund.getId(), refund.getOrderId(), e);
        }
    }

    private String generateRefundNo(String orderNo) {
        return PaymentConstants.REFUND_ORDER_PREFIX + orderNo + System.currentTimeMillis();
    }
}
