package shop.alien.lawyer.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.result.R;
import shop.alien.entity.store.LawyerConsultationOrder;
import shop.alien.entity.store.LifeNotice;
import shop.alien.entity.store.vo.WebSocketVo;
import shop.alien.lawyer.config.BaseRedisService;
import shop.alien.lawyer.config.WebSocketProcess;
import shop.alien.lawyer.controller.AliController;
import shop.alien.lawyer.feign.AlienStoreFeign;
import shop.alien.lawyer.listener.RedisKeyExpirationHandler;
import shop.alien.lawyer.service.OrderExpirationService;
import shop.alien.mapper.LawyerConsultationOrderMapper;
import shop.alien.mapper.LifeNoticeMapper;
import shop.alien.mapper.LifeUserMapper;
import shop.alien.util.common.DateUtils;
import shop.alien.util.common.constant.PaymentEnum;


import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 訂單過期處理服務實現類
 * 
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderExpirationServiceImpl implements OrderExpirationService, CommandLineRunner {

    @Value("${order.coefficient}")
    private String coefficient;

    @Value("${order.coefficients}")
    private String coefficients;

    private final BaseRedisService redisService;
    private final RedisKeyExpirationHandler expirationHandler;
    private final LawyerConsultationOrderMapper orderMapper;
    private final AliController aliController;
    private final LifeNoticeMapper lifeNoticeMapper;
    private final LifeUserMapper lifeUserMapper;
    private final WebSocketProcess webSocketProcess;
    private final AlienStoreFeign alienStoreFeign;

    /**
     * Redis key前綴：訂單支付超時
     */
    private static final String ORDER_PAYMENT_TIMEOUT_PREFIX = "lawyer:order:payment:timeout:";

    /**
     * Redis key前綴：訂單接单超時
     */
    private static final String ORDER_ACCEPT_TIMEOUT_PREFIX = "lawyer:order:accept:timeout:";

    /**
     * Redis key前綴：訂單退款超時
     */
    private static final String ORDER_REFUND_TIMEOUT_PREFIX = "lawyer:order:refund:timeout:";

    /**
     * Redis key前綴：订单超时完成
     */
    private static final String ORDER_COMPLETE_TIMEOUT_PREFIX = "lawyer:order:complete:timeout:";

    /**
     * 默認超時時間：30分鐘
     */
    private static final long DEFAULT_TIMEOUT_SECONDS = 30 * 60;

    /**
     * 系统发送者ID
     */
    private static final String SYSTEM_SENDER_ID = "system";

    /**
     * 初始化時註冊訂單支付超時處理器
     */
    @PostConstruct
    public void init() {
        // 註冊訂單支付超時處理器
        expirationHandler.registerHandler(ORDER_PAYMENT_TIMEOUT_PREFIX, this::handleExpiredOrderKey);
        log.info("訂單支付超時處理器註冊完成，前綴: {}", ORDER_PAYMENT_TIMEOUT_PREFIX);

        // 註冊订单待接单超时處理器
        expirationHandler.registerHandler(ORDER_ACCEPT_TIMEOUT_PREFIX, this::handleRefundOrderKey);
        log.info("訂單接单超時處理器註冊完成，前綴: {}", ORDER_ACCEPT_TIMEOUT_PREFIX);

        // 註冊訂單退款超時處理器
        expirationHandler.registerHandler(ORDER_REFUND_TIMEOUT_PREFIX, this::handleRefundOrderKey);
        log.info("訂單退款超時處理器註冊完成，前綴: {}", ORDER_REFUND_TIMEOUT_PREFIX);

        // 订单超时完成处理器
        expirationHandler.registerHandler(ORDER_COMPLETE_TIMEOUT_PREFIX, this::handleTimeOutCompleteOrderKey);
        log.info("订单已经完成，前綴: {}", ORDER_COMPLETE_TIMEOUT_PREFIX);
    }

    @Override
    public void run(String... args) {
        log.info("OrderExpirationService 初始化完成");
    }

    /**
     * 處理過期的訂單key
     * 
     * @param expiredKey 過期的key，格式：order:payment:timeout:{orderId}
     */
    private void handleExpiredOrderKey(String expiredKey) {
        try {
            // 從key中提取訂單ID
            String orderNo = expiredKey.replace(ORDER_PAYMENT_TIMEOUT_PREFIX, "");
            
            log.info("檢測到訂單支付超時，訂單no: {}", orderNo);
            
            // 處理訂單支付超時
            handleOrderPaymentTimeout(orderNo);
        } catch (Exception e) {
            log.error("處理過期訂單key失敗，key: {}", expiredKey, e);
        }
    }

    /**
     * 處理過期的訂單key
     *
     * @param expiredKey 過期的key，格式：order:payment:timeout:{orderId}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleRefundOrderKey(String expiredKey) {
        try {
            // 從key中提取訂單ID
            String orderNo = "";
            String refundReason = "";
            String title = "";
            String message = "";
            //律师未接单退款
            if (expiredKey.contains(ORDER_ACCEPT_TIMEOUT_PREFIX)) {
                orderNo = expiredKey.replace(ORDER_ACCEPT_TIMEOUT_PREFIX, "");
                refundReason = "律师未接单超時退款";
                title = "未接单通知";
                message = "您的编号为" + orderNo + "的订单已到48小时未被接单，订单金额将在1-3个工作日原路返还，请注意查收。";

                // 查詢訂單
                LambdaQueryWrapper<LawyerConsultationOrder> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(LawyerConsultationOrder::getOrderNumber, orderNo).last("LIMIT 1");
                LawyerConsultationOrder order = orderMapper.selectOne(queryWrapper);

                log.info("檢測到有訂單需要退款，訂單no: {}", orderNo);

                //通知
                LifeNotice lifeNotice = buildUserLifeNotice(order, title, message);
                WebSocketVo webSocketVo = buildWebSocketVo(lifeNotice);

                lifeNoticeMapper.insert(lifeNotice);
                webSocketProcess.sendMessage(lifeNotice.getReceiverId(), JSONObject.from(webSocketVo).toJSONString());

                log.info("系统通知发送成功，訂單no: {}", orderNo);

                // 處理訂單退款
                //aliController.processRefund(order.getAlipayNo(),  new BigDecimal(order.getOrderAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString(), refundReason,"");

                // 微信/支付宝退款
                Map<String, String> paramMap = new HashMap<>();
                refundParam(paramMap, order, refundReason);
                R refunds = alienStoreFeign.paymentRefunds(paramMap);

                if (refunds.getCode() == 200) {
                    log.info("訂單退款成功，訂單no: {}", orderNo);

                    //退款到账通知
                    LifeNotice lifeNotice2 = buildUserLifeNotice(order, "退款到账通知", "您的编号为" + orderNo + "的订单，订单金额已原路返还至您的支付渠道，请查收。");
                    WebSocketVo webSocketVo2 = buildWebSocketVo(lifeNotice2);
                    lifeNotice2.setCreatedTime(DateUtils.calcMinute(new Date(), 2));

                    lifeNoticeMapper.insert(lifeNotice2);
                    webSocketProcess.sendMessage(lifeNotice2.getReceiverId(), JSONObject.from(webSocketVo2).toJSONString());

                    log.info("系统通知发送成功，訂單no: {}", orderNo);

                    LawyerConsultationOrder update = new LawyerConsultationOrder();
                    update.setId(order.getId());
                    update.setOrderStatus(5);
                    update.setApplyRefundTime(new Date());
                    orderMapper.updateById( update);
                }
            }
            //申请退款 律师没处理
            if (expiredKey.contains(ORDER_REFUND_TIMEOUT_PREFIX)) {
                orderNo = expiredKey.replace(ORDER_REFUND_TIMEOUT_PREFIX, "");
                refundReason = "申请退款超时后退款";

                // 查詢訂單
                LambdaQueryWrapper<LawyerConsultationOrder> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(LawyerConsultationOrder::getOrderNumber, orderNo).last("LIMIT 1");
                LawyerConsultationOrder order = orderMapper.selectOne(queryWrapper);

                log.info("檢測到有訂單需要退款，訂單no: {}", orderNo);

                //同意退款通知
                LifeNotice lifeNotice = buildUserLifeNotice(order, "同意退款通知", "您的编号为" + orderNo + "的订单，律师已同意您的退款申请，订单金额将在1-3个工作日原路返还，请注意查收。");
                WebSocketVo webSocketVo = buildWebSocketVo(lifeNotice);

                lifeNoticeMapper.insert(lifeNotice);
                webSocketProcess.sendMessage(lifeNotice.getReceiverId(), JSONObject.from(webSocketVo).toJSONString());

                // 處理訂單退款
                //String refundResult = aliController.processRefund(order.getAlipayNo(), new BigDecimal(order.getOrderAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString(), refundReason, "");

                // 微信/支付宝退款
                Map<String, String> paramMap = new HashMap<>();
                refundParam(paramMap, order, refundReason);
                R refunds = alienStoreFeign.paymentRefunds(paramMap);

                if (refunds.getCode() == 200) {
                    log.info("訂單退款成功，訂單no: {}", orderNo);

                    //退款到账通知
                    LifeNotice lifeNotice2 = buildUserLifeNotice(order, "退款到账通知", "您的编号为" + orderNo + "的订单，订单金额已原路返还至您的支付渠道，请查收。");
                    WebSocketVo webSocketVo2 = buildWebSocketVo(lifeNotice2);
                    lifeNotice2.setCreatedTime(DateUtils.calcMinute(lifeNotice2.getCreatedTime(), 2));

                    lifeNoticeMapper.insert(lifeNotice2);
                    webSocketProcess.sendMessage(lifeNotice2.getReceiverId(), JSONObject.from(webSocketVo2).toJSONString());

                    log.info("系统通知发送成功，訂單no: {}", orderNo);

                    LawyerConsultationOrder update = new LawyerConsultationOrder();
                    update.setId(order.getId());
                    update.setOrderStatus(5);
                    update.setApplyRefundStatus("4");
                    update.setApplyRefundTime(new Date());
                    orderMapper.updateById(update);
                }
            }
        } catch (Exception e) {
            log.error("處理有訂單需要退款key失敗，key: {}", expiredKey, e);
        }
    }

    /**
     * 处理订单超时完成key
     *
     * @param expiredKey 過期的key，格式：lawyer:order:complete:timeout:{orderId}
     */
    private void handleTimeOutCompleteOrderKey(String expiredKey) {
        try {
            // 從key中提取訂單ID
            String orderNo = expiredKey.replace(ORDER_COMPLETE_TIMEOUT_PREFIX, "");

            log.info("订单超时已完成，订单no: {}", orderNo);

            // 處理訂單支付超時
            handleTimeOutCompleteOrder(orderNo);
        } catch (Exception e) {
            log.error("處理過期訂單key失敗，key: {}", expiredKey, e);
        }
    }

    private void refundParam(Map<String,String> paramMap,LawyerConsultationOrder order,String refundReason){
        //支付宝
        if ("1".equals(order.getPayType())) {
            paramMap.put("payType", PaymentEnum.ALIPAY.getType());
            paramMap.put("outTradeNo", order.getAlipayNo());
            paramMap.put("refundReason", refundReason);
            paramMap.put("refundAmount", new BigDecimal(order.getOrderAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
        }
        //微信
        if ("2".equals(order.getPayType())) {
            paramMap.put("payType", PaymentEnum.WECHAT_PAY.getType());
            paramMap.put("outTradeNo", order.getAlipayNo());
            paramMap.put("reason", refundReason);
            paramMap.put("refundAmount", order.getOrderAmount().toString());
            paramMap.put("totalAmount", order.getOrderAmount().toString());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOrderPaymentTimeout(String orderNum) {
        log.info("開始處理訂單支付超時，訂單no: {}", orderNum);
        
        try {
            // 查詢訂單
            LambdaQueryWrapper<LawyerConsultationOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LawyerConsultationOrder::getOrderNumber, orderNum).last("LIMIT 1");
            LawyerConsultationOrder order = orderMapper.selectOne(queryWrapper);
            if (order == null) {
                log.warn("訂單不存在，訂單no: {}", orderNum);
                return;
            }

            // 只處理待支付狀態的訂單
            if (order.getOrderStatus() != null && order.getOrderStatus() == 0) {
                log.info("訂單處於待支付狀態，開始取消訂單，訂單no: {}", orderNum);

                LawyerConsultationOrder lawyerConsultationOrder = new LawyerConsultationOrder();
                // 更新訂單狀態為已取消
                lawyerConsultationOrder.setOrderStatus(4); // 4:已取消
                lawyerConsultationOrder.setId(order.getId());
                lawyerConsultationOrder.setUpdatedTime(new Date());
                
                int updated = orderMapper.updateById(lawyerConsultationOrder);
                if (updated > 0) {
                    log.info("訂單支付超時，已自動取消訂單，訂單no: {}", orderNum);
                } else {
                    log.error("取消訂單失敗，訂單no: {}", orderNum);
                }
            } else {
                log.info("訂單狀態不是待支付，無需處理，訂單no: {}, 當前狀態: {}", orderNum, order.getOrderStatus());
            }
        } catch (Exception e) {
            log.error("處理訂單支付超時失敗，訂單no: {}", orderNum, e);
            throw e;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleTimeOutCompleteOrder(String orderNum) {
        log.info("开始处理订单完成，订单no: {}", orderNum);

        try {
            // 查詢訂單
            LambdaQueryWrapper<LawyerConsultationOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LawyerConsultationOrder::getOrderNumber, orderNum).last("LIMIT 1");
            LawyerConsultationOrder order = orderMapper.selectOne(queryWrapper);
            if (order == null) {
                log.warn("订单不存在，订单no: {}", orderNum);
                return;
            }

            // 只处理进行中的订单
            if (order.getOrderStatus() != null && order.getOrderStatus() == 2) {
                log.info("订单为进行中状态，开始完成订单，订单no: {}", orderNum);

                LawyerConsultationOrder lawyerConsultationOrder = new LawyerConsultationOrder();
                // 更新订单状态为已完成
                lawyerConsultationOrder.setOrderStatus(3); // 3:已完成
                lawyerConsultationOrder.setId(order.getId());
                lawyerConsultationOrder.setUpdatedTime(new Date());

                int updated = orderMapper.updateById(lawyerConsultationOrder);
                if (updated > 0) {
                    log.info("订单已经超时，已经自动完成，订单no: {}", orderNum);
                } else {
                    log.error("订单自动完成失败，订单no: {}", orderNum);
                }
            } else {
                log.info("订单不是进行中，无需处理，订单no: {}, 当前状态: {}", orderNum, order.getOrderStatus());
            }
        } catch (Exception e) {
            log.error("处理订单状态完成异常，订单no: {}", orderNum, e);
            throw e;
        }
    }

    @Override
    public void setOrderPaymentTimeout(String orderNumber, long timeoutSeconds) {
        if (orderNumber == null) {
            log.warn("訂單ID為null，無法設置支付超時監聽");
            return;
        }
        
        String key = ORDER_PAYMENT_TIMEOUT_PREFIX + orderNumber;
        long timeout = timeoutSeconds > 0 ? timeoutSeconds : 60 * Long.parseLong(coefficient);
        
        // 設置Redis key，帶過期時間
        // 當key過期時，會觸發RedisKeyExpirationListener
        redisService.setString(key, String.valueOf(orderNumber), timeout);
        
        log.info("設置訂單支付超時監聽，訂單NO: {}, 超時時間: {}秒, key: {}", orderNumber, timeout, key);
    }

    @Override
    public void setOrderAcceptTimeout(String orderNumber, long timeoutSeconds) {
        if (orderNumber == null) {
            log.warn("訂單ID為null，無法設置支付超時監聽");
            return;
        }

        String key = ORDER_ACCEPT_TIMEOUT_PREFIX + orderNumber;
        long timeout = timeoutSeconds > 0 ? timeoutSeconds : 60 * Long.parseLong(coefficients);

        // 設置Redis key，帶過期時間
        // 當key過期時，會觸發RedisKeyExpirationListener
        redisService.setString(key, String.valueOf(orderNumber), timeout);

        log.info("設置訂單接单超時監聽，訂單NO: {}, 超時時間: {}秒, key: {}", orderNumber, timeout, key);
    }

    @Override
    public void setOrderRefundTimeout(String orderNumber, long timeoutSeconds) {
        if (orderNumber == null) {
            log.warn("訂單ID為null，無法設置支付超時監聽");
            return;
        }

        String key = ORDER_REFUND_TIMEOUT_PREFIX + orderNumber;
        long timeout = timeoutSeconds > 0 ? timeoutSeconds : 60 * Long.parseLong(coefficients);

        // 設置Redis key，帶過期時間
        // 當key過期時，會觸發RedisKeyExpirationListener
        redisService.setString(key, String.valueOf(orderNumber), timeout);

        log.info("設置訂單退款超時監聽，訂單NO: {}, 超時時間: {}秒, key: {}", orderNumber, timeout, key);
    }

    @Override
    public void setOrderCompleteTimeout(String orderNumber, long timeoutSeconds) {
        if (orderNumber == null) {
            log.warn("订单NO为null，无法设置订单超时完成监听");
            return;
        }

        String key = ORDER_COMPLETE_TIMEOUT_PREFIX + orderNumber;
        long timeout = timeoutSeconds > 0 ? timeoutSeconds : 60 * Long.parseLong(coefficients);

        // 设置Redis key，带过期时间
        // 当key过期时，会触发RedisKeyExpirationListener
        redisService.setString(key, String.valueOf(orderNumber), timeout);

        log.info("设置订单超时完成监听，订单: {}, 超时时间: {}秒, key: {}", orderNumber, timeout, key);
    }

    /**
     * 取消訂單支付超時監聽（當訂單已支付時調用）
     * 
     * @param orderNumber 訂單NO
     */
    public void cancelOrderPaymentTimeout(String orderNumber) {
        if (orderNumber == null) {
            return;
        }
        
        String key = ORDER_PAYMENT_TIMEOUT_PREFIX + orderNumber;
        redisService.delete(key);
        
        log.info("取消訂單支付超時監聽，訂單ID: {}, key: {}", orderNumber, key);
    }

    @Override
    public void cancelOrderAcceptTimeout(String orderNumber) {
        if (orderNumber == null) {
            return;
        }

        String key = ORDER_ACCEPT_TIMEOUT_PREFIX + orderNumber;
        redisService.delete(key);

        log.info("取消訂單接单超時監聽，訂單ID: {}, key: {}", orderNumber, key);
    }

    @Override
    public void cancelOrderRefundTimeout(String orderNumber) {
        if (orderNumber == null) {
            return;
        }

        String key = ORDER_REFUND_TIMEOUT_PREFIX + orderNumber;
        redisService.delete(key);

        log.info("取消訂單退款超時監聽，訂單ID: {}, key: {}", orderNumber, key);
    }

    /**
     * 构建WebSocket消息对象
     *
     * @param lifeNotice 通知对象
     * @return WebSocketVo对象
     */
    private WebSocketVo buildWebSocketVo(LifeNotice lifeNotice) {
        WebSocketVo webSocketVo = new WebSocketVo();
        webSocketVo.setSenderId(SYSTEM_SENDER_ID);
        webSocketVo.setReceiverId(lifeNotice.getReceiverId());
        webSocketVo.setCategory("notice");
        webSocketVo.setNoticeType("1");
        webSocketVo.setIsRead(0);
        webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
        return webSocketVo;
    }

    private LifeNotice buildLifeNotice(LawyerConsultationOrder lawyerConsultationOrder,String title,String message){
        LifeNotice lifeNotice = new LifeNotice();
        lifeNotice.setSenderId(SYSTEM_SENDER_ID);
        lifeNotice.setBusinessId(lawyerConsultationOrder.getId());
        lifeNotice.setTitle(title);
        lifeNotice.setReceiverId("lawyer_" + lifeUserMapper.selectById(lawyerConsultationOrder.getClientUserId()).getUserPhone());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("message", message);
        lifeNotice.setContext(jsonObject.toJSONString());
        lifeNotice.setNoticeType(1);
        lifeNotice.setBusinessType(1);

        return lifeNotice;
    }

    private LifeNotice buildUserLifeNotice(LawyerConsultationOrder lawyerConsultationOrder,String title,String message){
        LifeNotice lifeNotice = new LifeNotice();
        lifeNotice.setSenderId(SYSTEM_SENDER_ID);
        lifeNotice.setBusinessId(lawyerConsultationOrder.getId());
        lifeNotice.setTitle(title);
        lifeNotice.setReceiverId("user_" + lifeUserMapper.selectById(lawyerConsultationOrder.getClientUserId()).getUserPhone());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("message", message);
        lifeNotice.setContext(jsonObject.toJSONString());
        lifeNotice.setNoticeType(1);
        lifeNotice.setBusinessType(1);
        lifeNotice.setCreatedTime(new Date());

        return lifeNotice;
    }
}

