package com.yc.ship.module.trade.framework.mq;


import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderDO;
import com.yc.ship.module.trade.dal.mysql.insurance.InsuranceMapper;
import com.yc.ship.module.trade.service.insurance.InsuranceService;
import com.yc.ship.module.trade.service.order.TradeOrderBizService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.handler.TradeOrderHandler;
import com.yc.ship.module.trade.service.ota.OtaStandardService;
import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
import com.yc.ship.module.trade.service.refund.TradeRefundService;
import com.yc.ship.module.trade.utils.InsuranceUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * &#064;Description ：交易类Mq接收器
 * &#064;Author ：qsl
 * &#064;Date ：2025/6/21 09:18
 */
@Component
@Slf4j
public class TradeMqReceiver {

    @Resource
    private TradeRefundService tradeRefundService;

    @Resource
    private List<TradeOrderHandler> tradeOrderHandlers;

    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;

    @Resource
    private TradeOrderPayService tradeOrderPayService;

    @Resource
    private TradeOrderBizService tradeOrderBizService;

    @Resource
    private OtaStandardService otaStandardService;

    @Resource
    private InsuranceUtil insuranceUtil;

    @Resource
    private TradePublishUtils tradePublishUtils;

    @Resource
    private InsuranceService insuranceService;


    /**
     * 处理订单创建成功消息
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.QUEUE_CREATE_SUCCESS, concurrency = "3")
    @TenantIgnore
    public void processOrderCreateSuccess(String data, Message message, Channel channel) throws IOException {
        log.error("收到下单创建成功消息：" + data);
        try {
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(Long.parseLong(data));
            if(tradeOrderDO==null){
                log.error("processOrderCreateSuccess订单不存在"+data);
            }else {
                tradeOrderHandlers.forEach(handler -> handler.processOrderCreateSuccess(tradeOrderDO));
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }
        } catch (Exception e) {
            log.error("下单创建成功MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 处理订单创建失败消息
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.QUEUE_CREATE_FAIL, concurrency = "3")
    @TenantIgnore
    public void processOrderCreateFail(String data, Message message, Channel channel) throws IOException {
        log.error("收到下单创建失败消息：" + data);
        try {
            //归还库存 等操作
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(Long.parseLong(data));
            tradeOrderHandlers.forEach(handler -> handler.afterSupplierOrderCreateFail(tradeOrderDO));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("下单创建失败MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 处理支付超时消息
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.QUEUE_PAY_TIMEOUT, concurrency = "3")
    public void processOrderPayTimeOut(String data, Message message, Channel channel) throws IOException {
        log.error("收到支付超时消息：" + data);
        try {
            //释放库存、通知供应商等操作
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(Long.parseLong(data));
            tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(tradeOrderDO));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("下支付超时MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 处理出票成功消息
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.QUEUE_PROCESS_SUCCESS, concurrency = "5")
    @TenantIgnore
    public void processOrderProcessSuccess(String data, Message message, Channel channel) throws IOException {
        log.error("收到出票成功消息：" + data);
        try {
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(Long.parseLong(data));
            tradeOrderHandlers.forEach(handler -> handler.afterProcessSuccess(tradeOrderDO));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("出票成功消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 处理出票失败消息
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.QUEUE_PROCESS_FAIL, concurrency = "3")
    @TenantIgnore
    public void processOrderProcessFail(String data, Message message, Channel channel) throws IOException {
        log.error("收到出票失败消息：" + data);
        try {
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(Long.parseLong(data));
            tradeOrderHandlers.forEach(handler -> handler.afterProcessFail(tradeOrderDO));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("出票失败消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 支付延迟消息处理
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_ORDER_PAY, concurrency = "3")
    @TenantIgnore
    public void processOrderPayDelay(String data, Message message, Channel channel) throws IOException {
        log.error("收到支付延迟消息：" + data);
        try {
            //验证订单是否支付，修改订单状态，发布支付超时消息
            tradeOrderPayService.orderPayTimeOutMessageHandler(Long.parseLong(data),false);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("支付延迟MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.QUEUE_SUPPLIER_REFUND_SUCCESS, concurrency = "2")
    @TenantIgnore
    public void processSupplierRefundSuccess(String data, Message message, Channel channel) throws IOException {
        log.error("收到供应商退款成功消息：" + data);
        try {
            tradeOrderHandlers.forEach(handler -> {
                try {
                    handler.afterRefundOrder(Long.parseLong(data));
                }catch (Exception e) {
                    log.error("退款成功处理异常",e);
                }
            });
            tradeRefundService.refundByPaymentTypeFromMq(Long.parseLong(data));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("供应商退款成功MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.QUEUE_REFUND_AUDIT, concurrency = "2")
    @TenantIgnore
    public void processRefundAuditResult(String data, Message message, Channel channel) throws IOException {
        log.error("收到退款审核结果消息：" + data);
        try {
            otaStandardService.notifyRefundAuditResult(Long.parseLong(data));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("收到退款审核结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 订单确认延迟消息处理
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_ORDER_CONFIRM, concurrency = "2")
    @TenantIgnore
    public void processConfirmOrderDelay(String data, Message message, Channel channel) throws IOException {
        log.info("收到二次确认订单延迟消息：" + data);
        try {

            tradeOrderBizService.handleConfirmOrderMessage(Long.parseLong(data));
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("二次确认订单延迟MQ处理出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.QUEUE_CHECK_ORDER_SUCCESS, concurrency = "2")
    @TenantIgnore
    public void processCheckOrderSuccess(String data, Message message, Channel channel) throws IOException {
        log.debug("收到订单核销成功结果消息：" + data);
        try {
            Map<String, Object> map = MapUtil.of("orderId",data);
            otaStandardService.otaCheckNotice(map);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("收到订单核销成功结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }


    @RabbitListener(queues = TradeMqConfig.QUEUE_CHECK_VOUCHER_SUCCESS, concurrency = "2")
    @TenantIgnore
    public void processCheckVoucherSuccess(String data, Message message, Channel channel) throws IOException {
        log.debug("收到票券核销成功结果消息：" + data);
        try {
            Map<String, Object> map = MapUtil.of("voucherId",data);
            otaStandardService.otaCheckNotice(map);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("收到票券核销成功结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.QUEUE_CHECK_VOUCHER_BASE_SUCCESS, concurrency = "2")
    @TenantIgnore
    public void processCheckVoucherBaseSuccess(String data, Message message, Channel channel) throws IOException {
        log.debug("收到子票核销成功结果消息：" + data);
        try {
            Map<String, Object> map = MapUtil.of("voucherBaseId",data);
            otaStandardService.otaCheckNotice(map);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("收到子票核销成功结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_UPDATE_ORDER_STATUS, concurrency = "2")
    @TenantIgnore
    public void processCheckUpdateOrderStatus(String data, Message message, Channel channel) throws IOException {
        log.error("收到订单/门票核销成功结果消息 orderId：" + data);
        try {
            Long orderId = Long.parseLong(data);
            tradeOrderHandlers.forEach(handler -> {
                try {
                    handler.afterCheckSuccess(orderId);
                }catch (Exception e) {
                    log.error("检票成功处理异常",e);
                }
            });
            tradeOrderRepositoryService.updateOrderStatusAfterCheck(orderId);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("收到订单/门票核销成功结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_CHECK_NOTIFY, concurrency = "2")
    @TenantIgnore
    public void processCheckDead(String data, Message message, Channel channel) throws IOException {
        log.debug("延迟核销MQ通知{}：", data);
        try {
            Map<String, Object> map = MapUtil.of("voucherId",data);
            otaStandardService.otaCheckNotice(map);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("延迟核销MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
    /**
     * 营销政策审核成功通知
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.ORDER_MARKETING_AUDIT, concurrency = "2")
    @TenantIgnore
    public void marketingAudit(String data, Message message, Channel channel) throws IOException {
        log.error("政策审核MQ通知{}：", data);
        try {
            //审核通过处理数据
            //marketingService.marketingAuditNotice(data);
            //审核成功处理金额退回
//            marketingService.marketingAuditNoticeNew(data);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("延迟核销MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 推送Ota产品价格库存
     * @param data
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_OTA_NOTIFY, concurrency = "2")
    @TenantIgnore
    public void processOtaProductPriceStock(String data, Message message, Channel channel) throws IOException {
        log.error("收到推送Ota产品价格库存结果消息 ：" + data);
        try {
            otaStandardService.otaProductPriceStockNotify(data);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("推送Ota产品价格库存结果消息MQ通知出现错误{}", e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_INSURANCE_QUERY, concurrency = "2")
    @TenantIgnore
    public void processInsuranceQuery(String data, Message message, Channel channel) throws IOException {
        log.error("收到保险查询结果消息 ：" + data);
        try {
            CommonResult commonResult = insuranceUtil.queryInsurance(data);
            if (!commonResult.isSuccess()) {
                log.error("保险查询结果消息通知出现错误{}", commonResult.getMsg());
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                String checkedData = (String) commonResult.getCheckedData();
                log.error("保险查询结果消息通知返回数据{}", checkedData);
                JSONObject jsonObject = JSONObject.parseObject(checkedData);
                BigDecimal paiedAmount = jsonObject.getBigDecimal("paiedAmount");
                JSONArray policies = jsonObject.getJSONArray("policies");
                if(policies == null) {
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                    return;
                }
                JSONObject policy = policies.getJSONObject(0);
                if(policy == null) {
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                    return;
                }
                String status = policy.getString("status");
                String service = policy.getString("service");
                String msg = policy.getString("msg");
                if("PROCESSING".equals(status)) {
                    log.error("保险查询结果，投保中，继续查询");
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                } else if("FAIL".equals(status)) {
                    log.error("保险查询结果，投保失败，不再查询");
                    Long externalPolicyNumber = policy.getLong("externalPolicyNumber");
                    insuranceService.handleInsuranceQuery(paiedAmount, "", externalPolicyNumber, status, service, msg);
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                } else if("SUCCESS".equals(status)) {
                    log.error("保险查询结果，投保成功，不再查询");
                    Long externalPolicyNumber = policy.getLong("externalPolicyNumber");
                    String policyNo = policy.getString("policyNo");
                    insuranceService.handleInsuranceQuery(paiedAmount, policyNo, externalPolicyNumber, status, service, msg);
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                }
            }
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("保险查询结果消息MQ通知出现错误", e);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        }


    }
}
