package edu.whut.trigger.basic;

import com.alibaba.fastjson.JSON;
import edu.whut.api.IMarketTradeService;
import edu.whut.api.dto.*;
import edu.whut.api.response.Response;
import edu.whut.domain.activity.model.entity.MarketProductEntity;
import edu.whut.domain.activity.model.entity.TrialBalanceEntity;
import edu.whut.domain.activity.model.valobj.GroupBuyActivityDiscountVO;
import edu.whut.domain.activity.service.IIndexGroupBuyMarketService;
import edu.whut.domain.trade.model.entity.*;
import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO;
import edu.whut.domain.trade.model.valobj.NotifyConfigVO;
import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO;
import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO;
import edu.whut.domain.trade.service.ITradeLockOrderService;
import edu.whut.domain.trade.service.ITradeRefundOrderService;
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
import edu.whut.types.enums.ResponseCode;
import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Objects;

@Slf4j
@Service
@RequiredArgsConstructor
public class MarketTradeService implements IMarketTradeService {
    //价格试算
    private final IIndexGroupBuyMarketService indexGroupBuyMarketService;
    //拼团锁单
    private final ITradeLockOrderService tradeOrderService;
    //拼团结算
    private final ITradeSettlementOrderService tradeSettlementOrderService;
    //退单
    private final ITradeRefundOrderService tradeRefundOrderService;

    /**
     * 锁定营销预支付订单（拼团 / 普通优惠）
     */
    @Override
    public Response<LockMarketPayOrderResponseDTO> lockMarketPayOrder(@RequestBody LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO) {
        try {
            /* ---------- 1. 基础参数提取与校验 ---------- */
            String userId     = lockMarketPayOrderRequestDTO.getUserId();
            String source     = lockMarketPayOrderRequestDTO.getSource();
            String channel    = lockMarketPayOrderRequestDTO.getChannel();
            String goodsId    = lockMarketPayOrderRequestDTO.getGoodsId();
            Long   activityId = lockMarketPayOrderRequestDTO.getActivityId();
            String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo();
            String teamId     = lockMarketPayOrderRequestDTO.getTeamId();       //可为空,对应参与拼团or创建拼团
            LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO();

            log.info("营销锁单开始执行：拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO));

            // 空值校验（任何一个关键字段为空则直接返回错误）
            boolean httpWithoutUrl =
                    "HTTP".equals(notifyConfigVO.getNotifyType())
                            && StringUtils.isBlank(notifyConfigVO.getNotifyUrl());

            if (StringUtils.isAnyBlank(userId, source, channel, goodsId)
                    || activityId == null
                    || httpWithoutUrl) {
                return Response.<LockMarketPayOrderResponseDTO>builder()
                        .code(ResponseCode.ILLEGAL_PARAMETER.getCode())
                        .info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
                        .build();
            }


            /* ---------- 2. 查询是否已存在未支付锁单 ---------- */
            MarketPayOrderEntity marketPayOrderEntity =
                    tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo);
            if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) {
                // 若已锁单未支付，直接返回原锁单信息（幂等）
                return buildSuccessResp(marketPayOrderEntity);
            }

            /* ---------- 3. 拼团目标人数校验 可能前端显示可参与，实际点击之后人数已满 ---------- */
            //（teamId 不为空表示 参与拼团 ）
            if (StringUtils.isNotBlank(teamId)) {
                // 查询当前拼团的 目标数量 已完成下单数量 锁单数量
                GroupBuyProgressVO progress = tradeOrderService.queryGroupBuyProgress(teamId);
                // 如果目标人数已满，则拒绝本次锁单 目前逻辑是结算完成LockCount也不会减。
                if (progress != null && Objects.equals(progress.getTargetCount(), progress.getLockCount())) {
                    log.info("交易锁单拦截-拼单目标已达成 userId={} teamId={} target={} lock={}",
                            userId, teamId, progress.getTargetCount(), progress.getLockCount());
                    return Response.<LockMarketPayOrderResponseDTO>builder()
                            .code(ResponseCode.E0006.getCode())
                            .info(ResponseCode.E0006.getInfo())
                            .build();
                }
            }

            /* ---------- 4. 调用营销服务进行优惠试算 ---------- */
            TrialBalanceEntity trialBalance = indexGroupBuyMarketService.indexMarketTrial(
                    MarketProductEntity.builder()
                            .userId(userId)
                            .source(source)
                            .channel(channel)
                            .goodsId(goodsId)
                            .activityId(activityId)
                            .build());

            // 人群限定，非目标人群不允许参与活动
            if (!trialBalance.getIsVisible() || !trialBalance.getIsEnable()){
                return Response.<LockMarketPayOrderResponseDTO>builder()
                        .code(ResponseCode.E0007.getCode())
                        .info(ResponseCode.E0007.getInfo())
                        .build();
            }

            //获取拼团活动配置信息
            GroupBuyActivityDiscountVO discountVO = trialBalance.getGroupBuyActivityDiscountVO();

            /* ---------- 5. 组装领域对象后调用真正的锁单 ---------- */
            marketPayOrderEntity = tradeOrderService.lockMarketPayOrder(
                    UserEntity.builder().userId(userId).build(),
                    PayActivityEntity.builder()
                            .teamId(teamId)
                            .activityId(activityId)
                            .activityName(discountVO.getActivityName())
                            .startTime(discountVO.getStartTime())
                            .endTime(discountVO.getEndTime())
                            .validTime(discountVO.getValidTime())
                            .targetCount(discountVO.getTarget())
                            .build(),
                    PayDiscountEntity.builder()
                            .source(source)
                            .channel(channel)
                            .goodsId(goodsId)
                            .goodsName(trialBalance.getGoodsName())
                            .originalPrice(trialBalance.getOriginalPrice())
                            .deductionPrice(trialBalance.getDeductionPrice())
                            .payPrice(trialBalance.getPayPrice())
                            .outTradeNo(outTradeNo)
                            .notifyConfigVO(
                                    // 构建回调通知对象
                                    NotifyConfigVO.builder()
                                            .notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType()))
                                            .notifyMQ(notifyConfigVO.getNotifyMQ())
                                            .notifyUrl(notifyConfigVO.getNotifyUrl())
                                            .build())
                            .build());

            log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity));

            /* ---------- 6. 构建成功返回 ---------- */
            return buildSuccessResp(marketPayOrderEntity);
        } catch (AppException e) {
            // 可预期的业务异常（如活动已过期、优惠额度不足等）
            log.error("拼团交易锁单业务异常 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
                    JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
            return Response.<LockMarketPayOrderResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .build();
        } catch (Exception e) {
            // 系统异常（NPE、RPC 调用失败等）
            log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
                    JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
            return Response.<LockMarketPayOrderResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 拼团交易结算
     * @param requestDTO 结算商品信息
     * @return
     */
    @Override
    public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(
            @RequestBody SettlementMarketPayOrderRequestDTO requestDTO) {
        log.info("营销交易组队结算开始: requestDTO={}", JSON.toJSONString(requestDTO));

        // —— 1. 参数校验 ——
        if (StringUtils.isAnyBlank(requestDTO.getUserId(), requestDTO.getSource(), requestDTO.getChannel(), requestDTO.getOutTradeNo())
                || requestDTO.getOutTradeTime() == null) {
            return Response.<SettlementMarketPayOrderResponseDTO>builder()
                    .code(ResponseCode.ILLEGAL_PARAMETER.getCode())
                    .info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
                    .build();
        }

        try {
            // —— 2. 调用结算服务 ——
            TradePaySuccessEntity successEntity = new TradePaySuccessEntity();
            BeanUtils.copyProperties(requestDTO, successEntity);

            //开始结算
            TradePaySettlementEntity settlement = tradeSettlementOrderService.settlementMarketPayOrder(successEntity);

            // —— 3. 构造返回 DTO ——
            SettlementMarketPayOrderResponseDTO responseDTO = new SettlementMarketPayOrderResponseDTO();
            BeanUtils.copyProperties(settlement, responseDTO);

            Response<SettlementMarketPayOrderResponseDTO> resp =
                    Response.<SettlementMarketPayOrderResponseDTO>builder()
                            .code(ResponseCode.SUCCESS.getCode())
                            .info(ResponseCode.SUCCESS.getInfo())
                            .data(responseDTO)
                            .build();

            log.info("营销交易组队结算完成: userId={} outTradeNo={} response={}",
                    requestDTO.getUserId(),
                    requestDTO.getOutTradeNo(),
                    JSON.toJSONString(resp));

            return resp;

        } catch (AppException e) {
            log.error("营销交易组队结算业务异常: userId={} requestDTO={}",
                    requestDTO.getUserId(),
                    JSON.toJSONString(requestDTO), e);
            return Response.<SettlementMarketPayOrderResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .build();
        } catch (Exception e) {
            log.error("营销交易组队结算失败: userId={} requestDTO={}",
                    requestDTO.getUserId(),
                    JSON.toJSONString(requestDTO), e);
            return Response.<SettlementMarketPayOrderResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }


    /**
     * 构建成功响应体，避免重复写样板代码
     */
    private Response<LockMarketPayOrderResponseDTO> buildSuccessResp(MarketPayOrderEntity entity) {
        return Response.<LockMarketPayOrderResponseDTO>builder()
                .code(ResponseCode.SUCCESS.getCode())
                .info(ResponseCode.SUCCESS.getInfo())
                .data(LockMarketPayOrderResponseDTO.builder()
                        .orderId(entity.getOrderId())
                        .originalPrice(entity.getOriginalPrice())
                        .deductionPrice(entity.getDeductionPrice())
                        .payPrice(entity.getPayPrice())
                        .teamId(entity.getTeamId())
                        .tradeOrderStatus(entity.getTradeOrderStatusEnumVO().getCode())
                        .build())
                .build();
    }

    /**
     * 用户退单接口
     * @param requestDTO 退单请求信息
     * @return
     */
    @Override
    public Response<RefundMarketPayOrderResponseDTO> refundMarketPayOrder(@RequestBody RefundMarketPayOrderRequestDTO requestDTO) {
        try {
            log.info("营销拼团退单开始:{} outTradeNo:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo());

            if (StringUtils.isBlank(requestDTO.getUserId()) || StringUtils.isBlank(requestDTO.getOutTradeNo()) || StringUtils.isBlank(requestDTO.getSource()) || StringUtils.isBlank(requestDTO.getChannel())) {
                return Response.<RefundMarketPayOrderResponseDTO>builder()
                        .code(ResponseCode.ILLEGAL_PARAMETER.getCode())
                        .info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
                        .build();
            }

            // 1. 退单服务
            TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(TradeRefundCommandEntity.builder()
                    .userId(requestDTO.getUserId())
                    .outTradeNo(requestDTO.getOutTradeNo())
                    .source(requestDTO.getSource())
                    .channel(requestDTO.getChannel())
                    .build());

            RefundMarketPayOrderResponseDTO responseDTO = RefundMarketPayOrderResponseDTO.builder()
                    .userId(tradeRefundBehaviorEntity.getUserId())
                    .orderId(tradeRefundBehaviorEntity.getOrderId())
                    .teamId(tradeRefundBehaviorEntity.getTeamId())
                    .code(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getCode())
                    .info(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getInfo())
                    .build();

            // 返回结果
            Response<RefundMarketPayOrderResponseDTO> response = Response.<RefundMarketPayOrderResponseDTO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(responseDTO)
                    .build();

            log.info("营销拼团退单完成:{} outTradeNo:{} response:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo(), JSON.toJSONString(response));

            return response;
        } catch (AppException e) {
            log.error("营销拼团退单异常:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
            return Response.<RefundMarketPayOrderResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .build();
        } catch (Exception e) {
            log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
            return Response.<RefundMarketPayOrderResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }
}
