package edu.whut.domain.trade.service.settlement;
import com.alibaba.fastjson.JSON;
import edu.whut.domain.trade.adapter.port.ITradePort;
import edu.whut.domain.trade.adapter.repository.ITradeRepository;
import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import edu.whut.domain.trade.model.entity.*;
import edu.whut.domain.trade.service.ITradeSettlementOrderService;
import edu.whut.domain.trade.service.ITradeTaskService;
import edu.whut.domain.trade.service.settlement.factory.TradeSettlementRuleFilterFactory;
import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList;
import edu.whut.types.enums.NotifyTaskHTTPEnumVO;
import edu.whut.types.exception.AppException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 拼团交易结算服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TradeSettlementOrderService implements ITradeSettlementOrderService {
    private final ITradeRepository repository;

    private final ITradePort port;

    private final ThreadPoolExecutor threadPoolExecutor;

    private final ITradeTaskService tradeTaskService;

    private final BusinessLinkedList<TradeSettlementRuleCommandEntity, TradeSettlementRuleFilterFactory.DynamicContext, TradeSettlementRuleFilterBackEntity> tradeSettlementRuleFilter;


    /**
     * 第三方支付渠道确认用户“支付成功”之后调用该函数，更新拼团订单状态为 已完成，并同步拼团人数。
     * @param tradePaySuccessEntity 交易支付订单实体对象
     * @return
     */
    @Override
    public TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity) throws Exception {
        log.info("拼团交易-支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo());
        // 1. 结算规则过滤
        TradeSettlementRuleCommandEntity command = new TradeSettlementRuleCommandEntity();
        BeanUtils.copyProperties(tradePaySuccessEntity, command);
        TradeSettlementRuleFilterBackEntity tradeSettlementRuleFilterBackEntity = tradeSettlementRuleFilter.apply(
                command, new TradeSettlementRuleFilterFactory.DynamicContext());
        String teamId=tradeSettlementRuleFilterBackEntity.getTeamId();
        // 2. 查询组团信息
        GroupBuyTeamEntity groupBuyTeamEntity = new GroupBuyTeamEntity();
        BeanUtils.copyProperties(tradeSettlementRuleFilterBackEntity, groupBuyTeamEntity);

        // 3. 构建聚合对象
        GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate = GroupBuyTeamSettlementAggregate.builder()
                .userEntity(UserEntity.builder().userId(tradePaySuccessEntity.getUserId()).build())
                .groupBuyTeamEntity(groupBuyTeamEntity)
                .tradePaySuccessEntity(tradePaySuccessEntity)
                .build();

        // 4. 更新数据库，拼团交易结算，若达到拼团人数，返回notifyTaskEntity发送回调通知，否则返回null不做处理
        NotifyTaskEntity notifyTaskEntity =repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate);

        // 5. 组队回调处理 - 处理失败也会有定时任务补偿，通过这样的方式，可以减轻任务调度，提高时效性
        if (null != notifyTaskEntity) {
            threadPoolExecutor.execute(() -> {
                Map<String, Integer> notifyResultMap = null;
                try {
                    notifyResultMap = tradeTaskService.execNotifyJob(notifyTaskEntity);
                    log.info("回调通知拼团完结 result:{}", JSON.toJSONString(notifyResultMap));
                } catch (Exception e) {
                    log.error("回调通知拼团完结失败 result:{}", JSON.toJSONString(notifyResultMap), e);
                    throw new AppException(e.getMessage());
                }
            });
        }

        // 6. 返回结算信息 - 公司中开发这样的流程时候，会根据外部需要进行值的设置
        return TradePaySettlementEntity.builder()
                .source(tradePaySuccessEntity.getSource())
                .channel(tradePaySuccessEntity.getChannel())
                .userId(tradePaySuccessEntity.getUserId())
                .teamId(teamId)
                .activityId(groupBuyTeamEntity.getActivityId())
                .outTradeNo(tradePaySuccessEntity.getOutTradeNo())
                .build();
    }
}
