package edu.whut.infrastructure.adapter.port;

import com.alibaba.fastjson.JSON;
import edu.whut.api.IMarketTradeService;               // Dubbo 接口
import edu.whut.api.dto.*;
import edu.whut.api.response.Response;
import edu.whut.domain.order.adapter.port.IProductPort;
import edu.whut.domain.order.model.entity.MarketPayDiscountEntity;
import edu.whut.domain.order.model.entity.ProductEntity;
import edu.whut.infrastructure.gateway.IGroupBuyMarketService; // Retrofit 接口
import edu.whut.infrastructure.gateway.ProductRPC;
import edu.whut.infrastructure.gateway.dto.ProductDTO;
import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import retrofit2.Call;

import java.util.Date;

/**
 * 商品与营销交易的适配层；同时支持 Retrofit(HTTP) 与 Dubbo(RPC)。
 * 通过配置属性 <pre>app.rpc.mode</pre> 动态切换调用通道：
 * <ul>
 *   <li>DUBBO  —— 默认，采用 Dubbo + Nacos</li>
 *   <li>HTTP  —— 走原 Retrofit HTTP 调用</li>
 * </ul>
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ProductPort implements IProductPort {

    /* -------------------- 公共配置 -------------------- */
    @Value("${app.config.group-buy-market.source}")
    private String source;
    @Value("${app.config.group-buy-market.chanel}")
    private String chanel;
    @Value("${app.config.group-buy-market.notify-url}")
    private String notifyUrl;
    @Value("${app.config.group-buy-market.notify-type}")
    private String notifyType;    // HTTP or MQ

    /* rpc.mode = DUBBO / HTTP，缺省 DUBBO */
    @Value("${app.rpc.mode:DUBBO}")
    private String rpcMode;

    /* -------------------- Retrofit 客户端 -------------------- */
    private final IGroupBuyMarketService retrofitService;

    /* -------------------- Dubbo 客户端 -------------------- */
    @DubboReference(version = "1.0.0", check = false)
    private final IMarketTradeService dubboService;

    /* -------------------- 产品 RPC -------------------- */
    private final ProductRPC productRPC;

    /* ============================================================ */
    /*                       商品查询接口                            */
    /* ============================================================ */
    @Override
    public ProductEntity queryProductByProductId(String productId) {
        ProductDTO dto = productRPC.queryProductByProductId(productId);
        return ProductEntity.builder()
                .productId(dto.getProductId())
                .productName(dto.getProductName())
                .productDesc(dto.getProductDesc())
                .price(dto.getPrice())
                .build();
    }

    /* ============================================================ */
    /*                       营销锁单                               */
    /* ============================================================ */
    @Override
    public MarketPayDiscountEntity lockMarketPayOrder(String userId,
                                                      String teamId,
                                                      Long activityId,
                                                      String productId,
                                                      String orderId) {
        LockMarketPayOrderRequestDTO req = buildLockReq(userId, teamId, activityId, productId, orderId);
        Response<LockMarketPayOrderResponseDTO> resp = invoke("lockMarketPayOrder", req);
        LockMarketPayOrderResponseDTO data = resp.getData();
        return MarketPayDiscountEntity.builder()
                .originalPrice(data.getOriginalPrice())
                .deductionPrice(data.getDeductionPrice())
                .payPrice(data.getPayPrice())
                .build();
    }

    /* ============================================================ */
    /*                       营销结算                               */
    /* ============================================================ */
    @Override
    public void settlementMarketPayOrder(String userId, String orderId, Date orderTime) {
        SettlementMarketPayOrderRequestDTO req = new SettlementMarketPayOrderRequestDTO();
        req.setSource(source);
        req.setChannel(chanel);
        req.setUserId(userId);
        req.setOutTradeNo(orderId);
        req.setOutTradeTime(orderTime);
        invoke("settlementMarketPayOrder", req);
    }

    /* ============================================================ */
    /*                       营销退单                               */
    /* ============================================================ */
    @Override
    public void refundMarketPayOrder(String userId, String orderId) {
        RefundMarketPayOrderRequestDTO req = new RefundMarketPayOrderRequestDTO();
        req.setSource(source);
        req.setChannel(chanel);
        req.setUserId(userId);
        req.setOutTradeNo(orderId);
        invoke("refundMarketPayOrder", req);
    }

    /* ************************************************************ */
    /*                         私有工具方法                          */
    /* ************************************************************ */

    /**
     * 根据模式调用对应通道
     */
    @SuppressWarnings("unchecked")
    private <REQ, RESP> Response<RESP> invoke(String method, REQ request) {
        log.info("[invoke] RPC 模式 = {}, 调用方法 = {}", rpcMode, method);
        try {
            Response<RESP> resp;
            if ("HTTP".equalsIgnoreCase(rpcMode)) {
                // ---------------- HTTP 调用 ----------------
                switch (method) {
                    case "lockMarketPayOrder":
                        resp = (Response<RESP>) httpLock((LockMarketPayOrderRequestDTO) request);
                        break;
                    case "settlementMarketPayOrder":
                        resp = (Response<RESP>) httpSettlement((SettlementMarketPayOrderRequestDTO) request);
                        break;
                    case "refundMarketPayOrder":
                        resp = (Response<RESP>) httpRefund((RefundMarketPayOrderRequestDTO) request);
                        break;
                    default:
                        throw new IllegalStateException("Unsupported HTTP method: " + method);
                }
            } else {
                // ---------------- Dubbo 调用 ----------------
                switch (method) {
                    case "lockMarketPayOrder":
                        resp = (Response<RESP>) dubboService.lockMarketPayOrder((LockMarketPayOrderRequestDTO) request);
                        break;
                    case "settlementMarketPayOrder":
                        resp = (Response<RESP>) dubboService.settlementMarketPayOrder((SettlementMarketPayOrderRequestDTO) request);
                        break;
                    case "refundMarketPayOrder":
                        resp = (Response<RESP>) dubboService.refundMarketPayOrder((RefundMarketPayOrderRequestDTO) request);
                        break;
                    default:
                        throw new IllegalStateException("Unsupported Dubbo method: " + method);
                }
            }

            // ----------- 统一异常处理 -----------
            if (resp == null) {
                throw new AppException("RPC_NULL", "rpc response null");
            }
            if (!"0000".equals(resp.getCode())) {
                throw new AppException(resp.getCode(), resp.getInfo());
            }
            log.info("[{}] 成功 userId={} request={} response={}", method, extractUserId(request), JSON.toJSONString(request), JSON.toJSONString(resp));
            return resp;
        } catch (AppException e) {
            throw e;
        } catch (Exception e) {
            log.error("[{}] 调用失败 request={}", method, JSON.toJSONString(request), e);
            throw new AppException("RPC_ERR", "rpc call error");
        }
    }

    /* ---------------- 单独封装 Retrofit 调用 ---------------- */
    private Response<LockMarketPayOrderResponseDTO> httpLock(LockMarketPayOrderRequestDTO req) throws Exception {
        Call<Response<LockMarketPayOrderResponseDTO>> call = retrofitService.lockMarketPayOrder(req);
        return call.execute().body();
    }

    private Response<SettlementMarketPayOrderResponseDTO> httpSettlement(SettlementMarketPayOrderRequestDTO req) throws Exception {
        Call<Response<SettlementMarketPayOrderResponseDTO>> call = retrofitService.settlementMarketPayOrder(req);
        return call.execute().body();
    }

    private Response<RefundMarketPayOrderResponseDTO> httpRefund(RefundMarketPayOrderRequestDTO req) throws Exception {
        Call<Response<RefundMarketPayOrderResponseDTO>> call = retrofitService.refundMarketPayOrder(req);
        return call.execute().body();
    }

    /* ---------------- DTO 构造 ---------------- */
    private LockMarketPayOrderRequestDTO buildLockReq(String userId, String teamId, Long activityId, String goodsId, String orderId) {
        LockMarketPayOrderRequestDTO dto = new LockMarketPayOrderRequestDTO();
        dto.setUserId(userId);
        dto.setTeamId(teamId);
        dto.setGoodsId(goodsId);
        dto.setActivityId(activityId);
        dto.setSource(source);
        dto.setChannel(chanel);
        dto.setOutTradeNo(orderId);
        if ("HTTP".equalsIgnoreCase(notifyType)) {
            dto.setNotifyUrl(notifyUrl);
        } else {
            dto.setNotifyMQ();
        }
        return dto;
    }

    /* ---- 从不同请求对象里提取 userId 仅用于日志 ---- */
    private String extractUserId(Object req) {
        if (req instanceof LockMarketPayOrderRequestDTO) {
            return ((LockMarketPayOrderRequestDTO) req).getUserId();
        } else if (req instanceof SettlementMarketPayOrderRequestDTO) {
            return ((SettlementMarketPayOrderRequestDTO) req).getUserId();
        } else if (req instanceof RefundMarketPayOrderRequestDTO) {
            return ((RefundMarketPayOrderRequestDTO) req).getUserId();
        }
        return "-";
    }
}
