package com.gxwebsoft.glt.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
import com.gxwebsoft.shop.entity.ShopOrderGoods;
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
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.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 水票撤销（订单取消/退款成功后的清理）：
 * - 取消/隐藏用户水票（glt_user_ticket.deleted=1）
 * - 删除未完成的释放计划（glt_user_ticket_release.deleted=1, status!=1）
 * - 删除未完成的送水订单（glt_ticket_order.deleted=1, delivery_status!=40）
 *
 * <p>说明：该操作需保证幂等；若无关联水票则无任何副作用。</p>
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GltTicketRevokeService {

    /** release.status：已释放 */
    private static final int RELEASE_STATUS_DONE = 1;
    /** ticketOrder.deliveryStatus：已完成 */
    private static final int TICKET_ORDER_DELIVERY_STATUS_FINISHED = 40;

    private final GltUserTicketService gltUserTicketService;
    private final GltUserTicketReleaseService gltUserTicketReleaseService;
    private final GltTicketOrderService gltTicketOrderService;
    private final ShopOrderGoodsService shopOrderGoodsService;

    @Transactional(rollbackFor = Exception.class)
    public int revokeByShopOrder(Integer tenantId, Integer shopOrderId, String shopOrderNo, String reason) {
        if (tenantId == null) {
            return 0;
        }
        if (shopOrderId == null && StrUtil.isBlank(shopOrderNo)) {
            return 0;
        }

        LambdaQueryWrapper<GltUserTicket> qw = new LambdaQueryWrapper<GltUserTicket>()
            .eq(GltUserTicket::getTenantId, tenantId)
            .eq(GltUserTicket::getDeleted, 0);

        if (shopOrderId != null && StrUtil.isNotBlank(shopOrderNo)) {
            qw.and(w -> w.eq(GltUserTicket::getOrderId, shopOrderId).or().eq(GltUserTicket::getOrderNo, shopOrderNo));
        } else if (shopOrderId != null) {
            qw.eq(GltUserTicket::getOrderId, shopOrderId);
        } else {
            qw.eq(GltUserTicket::getOrderNo, shopOrderNo);
        }

        List<GltUserTicket> tickets = gltUserTicketService.list(qw);

        // 兼容历史数据：部分水票只记录了 orderGoodsId，未记录 orderId/orderNo
        if ((tickets == null || tickets.isEmpty()) && shopOrderId != null) {
            try {
                List<ShopOrderGoods> goodsList = shopOrderGoodsService.list(
                    new LambdaQueryWrapper<ShopOrderGoods>()
                        .select(ShopOrderGoods::getId)
                        .eq(ShopOrderGoods::getTenantId, tenantId)
                        .eq(ShopOrderGoods::getOrderId, shopOrderId)
                );
                List<Integer> orderGoodsIds = goodsList == null ? List.of() : goodsList.stream()
                    .map(ShopOrderGoods::getId)
                    .filter(id -> id != null && id > 0)
                    .distinct()
                    .toList();
                if (!orderGoodsIds.isEmpty()) {
                    tickets = gltUserTicketService.list(
                        new LambdaQueryWrapper<GltUserTicket>()
                            .eq(GltUserTicket::getTenantId, tenantId)
                            .eq(GltUserTicket::getDeleted, 0)
                            .in(GltUserTicket::getOrderGoodsId, orderGoodsIds)
                    );
                }
            } catch (Exception e) {
                log.warn("撤销水票：通过orderGoodsId兜底反查失败 - tenantId={}, shopOrderId={}", tenantId, shopOrderId, e);
            }
        }
        if (tickets == null || tickets.isEmpty()) {
            return 0;
        }

        LocalDateTime now = LocalDateTime.now();
        int revoked = 0;
        // 不强制覆盖 comments，避免影响后台人工备注；reason 仅用于日志。
        String reasonForLog = StrUtil.isBlank(reason) ? "订单取消/退款撤销水票" : reason.trim();

        // 去重（避免 orderId/orderNo 与 orderGoodsId 两种路径重复命中）
        Set<Integer> seen = new HashSet<>();
        for (GltUserTicket t : tickets) {
            if (t == null || t.getId() == null) {
                continue;
            }
            if (!seen.add(t.getId())) {
                continue;
            }

            Integer userTicketId = t.getId();

            // 1) 删除未完成的送水订单（避免继续配送/接单/确认）
            try {
                LambdaUpdateWrapper<GltTicketOrder> uw = new LambdaUpdateWrapper<GltTicketOrder>()
                    .eq(GltTicketOrder::getTenantId, tenantId)
                    .eq(GltTicketOrder::getDeleted, 0)
                    .eq(GltTicketOrder::getUserTicketId, userTicketId)
                    // 兼容历史/脏数据：deliveryStatus 为空时也按“未完成”处理
                    .and(w -> w.ne(GltTicketOrder::getDeliveryStatus, TICKET_ORDER_DELIVERY_STATUS_FINISHED)
                        .or().isNull(GltTicketOrder::getDeliveryStatus))
                    .set(GltTicketOrder::getDeleted, 1)
                    .set(GltTicketOrder::getUpdateTime, now);
                gltTicketOrderService.update(null, uw);
            } catch (Exception e) {
                log.warn("撤销送水订单失败(继续尝试撤销水票/释放计划) - tenantId={}, shopOrderId={}, userTicketId={}",
                    tenantId, shopOrderId, userTicketId, e);
            }

            // 2) 删除未完成的释放计划（防止后续继续自动释放）
            try {
                LambdaUpdateWrapper<GltUserTicketRelease> uw = new LambdaUpdateWrapper<GltUserTicketRelease>()
                    .eq(GltUserTicketRelease::getTenantId, tenantId)
                    .eq(GltUserTicketRelease::getDeleted, 0)
                    .eq(GltUserTicketRelease::getUserTicketId, userTicketId)
                    // status 为空时也视为“未完成”
                    .and(w -> w.ne(GltUserTicketRelease::getStatus, RELEASE_STATUS_DONE)
                        .or().isNull(GltUserTicketRelease::getStatus))
                    .set(GltUserTicketRelease::getDeleted, 1)
                    .set(GltUserTicketRelease::getUpdateTime, now);
                gltUserTicketReleaseService.update(null, uw);
            } catch (Exception e) {
                log.warn("撤销水票释放计划失败(继续尝试撤销水票) - tenantId={}, shopOrderId={}, userTicketId={}",
                    tenantId, shopOrderId, userTicketId, e);
            }

            // 3) 撤销水票本身（软删除；幂等）
            boolean ok = gltUserTicketService.update(
                null,
                new LambdaUpdateWrapper<GltUserTicket>()
                    .eq(GltUserTicket::getTenantId, tenantId)
                    .eq(GltUserTicket::getDeleted, 0)
                    .eq(GltUserTicket::getId, userTicketId)
                    .set(GltUserTicket::getDeleted, 1)
                    .set(GltUserTicket::getUpdateTime, now)
            );
            if (ok) {
                revoked++;
            }
        }

        log.info("撤销水票完成 - tenantId={}, shopOrderId={}, shopOrderNo={}, tickets={}, reason={}",
            tenantId, shopOrderId, shopOrderNo, revoked, reasonForLog);
        return revoked;
    }
}
