package com.liquidnet.service.goblin.service.impl;

import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import com.liquidnet.common.third.sqb.param.request.CouponQueryRequest;
import com.liquidnet.common.third.sqb.param.request.CouponRefundRequest;
import com.liquidnet.common.third.sqb.param.request.CouponStatusSyncRequest;
import com.liquidnet.common.third.sqb.param.response.data.CouponQueryData;
import com.liquidnet.common.third.sqb.param.response.data.CouponRefundData;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinSqbService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.GoblinSqbRedisUtils;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 收钱吧订单服务实现
 */
@Slf4j
@Service
public class GoblinSqbServiceImpl implements IGoblinSqbService {

    @Autowired
    private GoblinSqbRedisUtils goblinSqbRedisUtils;

    @Autowired
    private GoblinRedisUtils goblinRedisUtils;

    @Autowired
    private GoblinMongoUtils goblinMongoUtils;

    @Autowired
    private QueueUtils queueUtils;

    @Autowired
    private SqbBiz sqbBiz;
    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    // ================================ 获取券码 ================================

    @Override
    public ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId) {
        log.info("[收钱吧券码] 开始获取 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
        if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单未支付，无法获取券码");

        // 幂等：已存在则直接返回
        if (orderVo.getCouponQrCode() != null && !orderVo.getCouponQrCode().isEmpty()) {
            GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
            couponVo.setCouponSn(orderVo.getCouponSn());
            couponVo.setCouponQrCode(orderVo.getCouponQrCode());
            couponVo.setCouponExpireTime(orderVo.getCouponExpireTime());
            return ResponseDto.success(couponVo);
        }

        // 调用收钱吧查询券码
        CouponQueryRequest req = new CouponQueryRequest();
        req.setAppid(sqbBiz.getSqbConfig().getAppId());
        req.setSeller(buildSeller());

        CouponQueryData couponData = sqbBiz.queryCoupon(req);
        if (couponData == null) return ResponseDto.failure("获取券码失败");

        // 更新订单 coupon 字段
        String now = LocalDateTime.now().format(DTF);
        orderVo.setCouponSn(couponData.getVoucherNo());
        orderVo.setCouponQrCode(couponData.getUrl());
        orderVo.setCouponExpireTime(couponData.getOperationTime());
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        // 券码信息保存在 Redis，MySQL和MongoDB商城基础模型无此字段，无需同步

        GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
        couponVo.setCouponSn(couponData.getVoucherNo());
        couponVo.setCouponQrCode(couponData.getUrl());
        couponVo.setCouponExpireTime(couponData.getOperationTime());

        log.info("[收钱吧券码] 获取成功，orderId={}", orderId);
        return ResponseDto.success(couponVo);
    }

    // ================================ 申请退款 ================================

    @Override
    public ResponseDto<Boolean> refund(String userId, String orderId) {
        log.info("[收钱吧退款] 开始 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
        if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单状态不可退款");
        if (Integer.valueOf(1).equals(orderVo.getCouponUsedStatus())) return ResponseDto.failure("券码已核销，不可退款");

        // 更新状态为退款中
        String now = LocalDateTime.now().format(DTF);
        orderVo.setStatus(4);
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        syncOrderStatus(orderId, 4);

        try {
            // 调用收钱吧退款
            CouponRefundRequest refundReq = new CouponRefundRequest();
            refundReq.setAppid(sqbBiz.getSqbConfig().getAppId());
            refundReq.setSeller(buildSeller());
            refundReq.setRequestSource("EXTERN");
            refundReq.setRequestId(IDGenerator.nextSnowId());

            CouponRefundRequest.RefundInfo refundInfo = new CouponRefundRequest.RefundInfo();
            // amount 字段待接入实际金额（GoblinSqbOrderVo 需补充 amount）
            refundInfo.setApplyAmount(0L); // TODO: 替换为实际订单金额
            refundInfo.setType((byte) 2); // 2-按金额退款
            refundInfo.setRefundReason("用户申请退款");
            refundReq.setRefundInfo(refundInfo);

            CouponRefundData refundData = sqbBiz.refundCoupon(refundReq);
            if (refundData == null) {
                // 退款失败，回滚状态
                orderVo.setStatus(1);
                orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
                goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
                syncOrderStatus(orderId, 1);
                return ResponseDto.failure("退款失败，请稍后重试");
            }

            // 退款成功
            orderVo.setStatus(3);
            orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            goblinRedisUtils.incrSkuStock(null, orderVo.getSkuId(), orderVo.getQuantity());

            syncOrderStatus(orderId, 3);
            log.info("[收钱吧退款] 退款成功，orderId={}", orderId);
            return ResponseDto.success(Boolean.TRUE);

        } catch (Exception e) {
            log.error("[收钱吧退款] 退款异常，orderId={}，回滚 status=1", orderId, e);
            orderVo.setStatus(1);
            orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            syncOrderStatus(orderId, 1);
            return ResponseDto.failure("退款失败：" + e.getMessage());
        }
    }

    // ================================ 同步核销状态 ================================

    @Override
    public ResponseDto<Boolean> syncCouponStatus(String userId, String orderId) {
        log.info("[收钱吧核销同步] 开始 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");

        CouponStatusSyncRequest req = new CouponStatusSyncRequest();
        req.setAppid(sqbBiz.getSqbConfig().getAppId());
        req.setRedeemSource("EXTERN");
        // TODO: 填充 voucherNos（券号列表）、redeemMerchantId、redeemExternalOrderSn、clientSn、status
        //       需要从 orderVo 中获取 couponSn 和其他必要字段
        if (orderVo.getCouponSn() != null) {
            req.setVoucherNos(java.util.Collections.singletonList(orderVo.getCouponSn()));
        }
        req.setRedeemMerchantId(sqbBiz.getSqbConfig().getMerchantId());
        req.setRedeemExternalOrderSn(IDGenerator.nextSnowId());
        req.setClientSn("terminal_001"); // TODO: 配置终端号
        req.setStatus((byte) 1); // 1-已核销

        boolean couponUsed = sqbBiz.syncCouponStatus(req);
        if (couponUsed) {
            String now = LocalDateTime.now().format(DTF);
            orderVo.setStatus(2);
            orderVo.setCouponUsedStatus(1);
            orderVo.setUpdatedAt(now);
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            syncOrderStatus(orderId, 2);
            log.info("[收钱吧核销同步] 核销成功，orderId={}", orderId);
        }
        return ResponseDto.success(couponUsed);
    }

    // ================================ 自动退款（定时任务） ================================

    @Override
    public ResponseDto<String> autoRefundByPerformance(String performancesId) {
        log.info("[收钱吧自动退款] 开始处理演出 performancesId={}", performancesId);

        // 查询该演出下 status=1（已支付）的订单（MySQL）
        // TODO: 通过 GoblinSqbOrderMapper 查询（需注入后解注释）
        // LambdaQueryWrapper<GoblinSqbOrder> query = new LambdaQueryWrapper<>();
        // query.eq(GoblinSqbOrder::getPerformancesId, performancesId).eq(GoblinSqbOrder::getStatus, 1);
        // List<GoblinSqbOrder> orders = goblinSqbOrderMapper.selectList(query);

        int successCount = 0;
        int failCount = 0;

        // TODO: 取消注释并接入 GoblinSqbOrderMapper 后启用
        // for (GoblinSqbOrder order : orders) {
        //     try {
        //         ResponseDto<Boolean> result = refund(order.getUserId(), order.getOrderId());
        //         if (result != null && result.isSuccess()) {
        //             successCount++;
        //         } else {
        //             log.warn("[收钱吧自动退款] 订单退款失败 orderId={}", order.getOrderId());
        //             failCount++;
        //         }
        //     } catch (Exception e) {
        //         log.error("[收钱吧自动退款] 订单退款异常 orderId={}", order.getOrderId(), e);
        //         failCount++;
        //     }
        // }

        String summary = String.format("演出 %s 自动退款完成：成功 %d 笔，失败 %d 笔", performancesId, successCount, failCount);
        log.info("[收钱吧自动退款] {}", summary);
        return ResponseDto.success(summary);
    }

    // ================================ 订单列表 ================================

    @Override
    public ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId) {
        log.info("[收钱吧订单列表] userId={}", userId);

        List<String> orderIds = goblinRedisUtils.getOrderList(userId);
        if (CollectionUtils.isEmpty(orderIds)) {
            return ResponseDto.success(Collections.emptyList());
        }

        List<GoblinSqbOrderDetailVo> result = new ArrayList<>();
        for (String orderId : orderIds) {
            GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
            if (storeOrderVo == null) continue;

            // 取第一个 orderSkuId 判断 skuType
            List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
            if (CollectionUtils.isEmpty(orderSkuVoIds)) continue;
            GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
            if (skuVo == null) continue;

            // 过滤：只处理 skuType=33 的收钱吧订单
            if (!Integer.valueOf(33).equals(skuVo.getSkuType())) continue;

            GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
            result.add(buildDetailVo(storeOrderVo, skuVo, sqbOrderVo));
        }

        // 按创建时间倒序排列
        result.sort((a, b) -> {
            if (a.getCreatedAt() == null) return 1;
            if (b.getCreatedAt() == null) return -1;
            return b.getCreatedAt().compareTo(a.getCreatedAt());
        });

        log.info("[收钱吧订单列表] userId={}, 共 {} 条", userId, result.size());
        return ResponseDto.success(result);
    }

    // ================================ 订单详情 ================================

    @Override
    public ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId) {
        log.info("[收钱吧订单详情] userId={}, orderId={}", userId, orderId);

        GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
        if (storeOrderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(storeOrderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");

        List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
        if (CollectionUtils.isEmpty(orderSkuVoIds)) return ResponseDto.failure("订单数据异常");
        GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
        if (skuVo == null) return ResponseDto.failure("订单商品数据异常");

        // 校验是收钱吧订单
        if (!Integer.valueOf(33).equals(skuVo.getSkuType())) {
            return ResponseDto.failure("该订单非收钱吧订单");
        }

        GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        GoblinSqbOrderDetailVo detailVo = buildDetailVo(storeOrderVo, skuVo, sqbOrderVo);

        log.info("[收钱吧订单详情] 查询成功，orderId={}", orderId);
        return ResponseDto.success(detailVo);
    }


    // ================================ 私有辅助方法 ================================

    private CommonRequest.Seller buildSeller() {
        CommonRequest.Seller seller = new CommonRequest.Seller();
        seller.setMerchantId(sqbBiz.getSqbConfig().getMerchantId());
        seller.setMerchantUserId(sqbBiz.getSqbConfig().getMerchantUserId());
        seller.setRole(sqbBiz.getSqbConfig().getRole());
        return seller;
    }


    private GoblinSqbOrderDetailVo buildDetailVo(GoblinStoreOrderVo storeOrderVo,
                                                 GoblinOrderSkuVo skuVo,
                                                 GoblinSqbOrderVo sqbOrderVo) {
        GoblinSqbOrderDetailVo detailVo = new GoblinSqbOrderDetailVo();
        // 来自 GoblinStoreOrderVo
        detailVo.setOrderId(storeOrderVo.getOrderId());
        detailVo.setOrderCode(storeOrderVo.getOrderCode());
        detailVo.setStatus(storeOrderVo.getStatus());
        detailVo.setPriceActual(storeOrderVo.getPriceActual());
        detailVo.setCreatedAt(storeOrderVo.getCreatedAt());
        detailVo.setPayTime(storeOrderVo.getPayTime());
        // 来自 GoblinOrderSkuVo
        detailVo.setSpuId(skuVo.getSpuId());
        detailVo.setSpuName(skuVo.getSpuName());
        detailVo.setSkuId(skuVo.getSkuId());
        detailVo.setSkuName(skuVo.getSkuName());
        detailVo.setSkuImage(skuVo.getSkuImage());
        detailVo.setQuantity(skuVo.getNum());
        // 来自 GoblinSqbOrderVo
        if (sqbOrderVo != null) {
            detailVo.setSqbStatus(sqbOrderVo.getStatus());
            detailVo.setPerformancesId(sqbOrderVo.getPerformancesId());
            detailVo.setSqbAcquiringSn(sqbOrderVo.getSqbAcquiringSn());
            detailVo.setCouponSn(sqbOrderVo.getCouponSn());
            detailVo.setCouponQrCode(sqbOrderVo.getCouponQrCode());
            detailVo.setCouponExpireTime(sqbOrderVo.getCouponExpireTime());
            detailVo.setCouponUsedStatus(sqbOrderVo.getCouponUsedStatus());
        }
        return detailVo;
    }

    /**
     * 构建收钱吧请求唯一ID，规则：AppCode（4位）+ id，总长不超过40位。
     *
     * @param id 业务唯一标识（如雪花ID）
     * @return 不超过40位的请求ID字符串
     */
    private String buildRequestId(String id) {
        String appCode = sqbBiz.getSqbConfig().getAppCode();
        if (appCode == null) appCode = "";
        String raw = appCode + id;
        return raw.length() > 40 ? raw.substring(0, 40) : raw;
    }

    /**
     * 构建收钱吧订单标题，不超过32位。
     *
     * @param name 商品名称
     * @return 不超过32位的标题字符串
     */
    private String buildTitle(String name) {
        if (name == null || name.isEmpty()) return "商品支付";
        return name.length() > 32 ? name.substring(0, 32) : name;
    }


    private void syncOrderStatus(String orderId, int status) {
        GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
        if (storeOrderVo == null) return;

        String now = LocalDateTime.now().format(DTF);
        storeOrderVo.setStatus(status);
        if (status == 1) { // 支付成功
            storeOrderVo.setPayTime(now);
        }

        // 1. 同步 Redis
        goblinRedisUtils.setGoblinOrder(orderId, storeOrderVo);

        // 2. 同步 MongoDB
        goblinMongoUtils.updateGoblinStoreOrderVo(orderId, storeOrderVo);

        // 3. 同步 MySQL (复用下单 MQ 发送 Update 语句)
        String sql;
        Object[] data;
        if (status == 1) {
            sql = "UPDATE goblin_store_order SET status = ?, pay_time = ?, updated_at = ? WHERE order_id = ?";
            data = new Object[]{status, now, now, orderId};
        } else {
            sql = "UPDATE goblin_store_order SET status = ?, updated_at = ? WHERE order_id = ?";
            data = new Object[]{status, now, orderId};
        }

        java.util.LinkedList<String> sqls = new java.util.LinkedList<>();
        sqls.add(sql);
        java.util.LinkedList<Object[]> sqlData = new java.util.LinkedList<>();
        sqlData.add(data);

        if (queueUtils != null) {
            queueUtils.sendMsgByRedis(com.liquidnet.service.base.constant.MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
                    com.liquidnet.service.base.SqlMapping.gets(sqls, sqlData));
        }
    }
}
