package com.seer.teach.pay.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seer.teach.pay.entity.PayMerchantRevenueDetailEntity;
import com.seer.teach.pay.enums.MerchantRevenueWithdrawStatusEnum;
import com.seer.teach.pay.mapper.PayMerchantRevenueDetailMapper;
import com.seer.teach.pay.service.IPayMerchantAccountService;
import com.seer.teach.pay.service.IPayMerchantRevenueDetailService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Slf4j
@Service
public class PayMerchantRevenueDetailServiceImpl extends ServiceImpl<PayMerchantRevenueDetailMapper, PayMerchantRevenueDetailEntity> implements IPayMerchantRevenueDetailService {

    private final IPayMerchantAccountService merchantAccountService;

    @Override
    public List<PayMerchantRevenueDetailEntity> getRevenueDetailsByMerchantUserId(Long merchantUserId) {
        return super.list(new LambdaQueryWrapper<>(PayMerchantRevenueDetailEntity.class).eq(PayMerchantRevenueDetailEntity::getMerchantUserId, merchantUserId)
                .eq(PayMerchantRevenueDetailEntity::getTransactionStatus, "PAID")
                .eq(PayMerchantRevenueDetailEntity::getSettlementStatus, PayMerchantRevenueDetailEntity.SETTLEMENT_STATUS_SETTLED)
                .in(PayMerchantRevenueDetailEntity::getWithdrawStatus, Arrays.asList(MerchantRevenueWithdrawStatusEnum.NOT_WITHDRAWN.getCode(), MerchantRevenueWithdrawStatusEnum.PARTIALLY_WITHDRAWN.getCode())));
    }

    @Override
    public List<PayMerchantRevenueDetailEntity> getUnsettledRevenueDetailsBeforeCutoff(LocalDateTime cutoffTime) {
        return super.list(new LambdaQueryWrapper<PayMerchantRevenueDetailEntity>()
                .lt(PayMerchantRevenueDetailEntity::getTransactionTime, cutoffTime)
                .eq(PayMerchantRevenueDetailEntity::getTransactionStatus, "PAID")
                .eq(PayMerchantRevenueDetailEntity::getSettlementStatus, PayMerchantRevenueDetailEntity.SETTLEMENT_STATUS_UNSETTLED));
    }

    @Override
    public void markRevenueAsSettled(Collection<Integer> detailIds) {
        super.update(new LambdaUpdateWrapper<>(PayMerchantRevenueDetailEntity.class)
                .set(PayMerchantRevenueDetailEntity::getSettlementStatus, PayMerchantRevenueDetailEntity.SETTLEMENT_STATUS_SETTLED)
                .in(PayMerchantRevenueDetailEntity::getId, detailIds));
    }

    @Override
    public List<PayMerchantRevenueDetailEntity> listByPayOrderSn(String payOrderSn) {
        return super.list(new LambdaQueryWrapper<PayMerchantRevenueDetailEntity>()
                .eq(PayMerchantRevenueDetailEntity::getPayOrderSn, payOrderSn));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean settleMerchantRevenue(LocalDateTime cutoffDateTime) {
        List<PayMerchantRevenueDetailEntity> unsettledRevenueDetails = getUnsettledRevenueDetailsBeforeCutoff(cutoffDateTime);
        if (CollUtil.isEmpty(unsettledRevenueDetails)) {
            return true;
        }
        Map<Long, List<PayMerchantRevenueDetailEntity>> merchantRevenueMap = unsettledRevenueDetails.stream()
                .collect(Collectors.groupingBy(
                        PayMerchantRevenueDetailEntity::getMerchantUserId, Collectors.toList()));
        log.info("共涉及 {} 个商家的收益结算", merchantRevenueMap.size());
        merchantRevenueMap.forEach((merchantUserId, details) -> {
            try {
                log.info("开始更新商家 {} 的账户余额", merchantUserId);

                BigDecimal revenueAmount = BigDecimal.ZERO;
                Collection<Integer> detailIds = new HashSet<>();
                for (PayMerchantRevenueDetailEntity detail : details) {
                    detailIds.add(detail.getId());
                    revenueAmount = revenueAmount.add(detail.getActualRevenue());
                }
                // 解冻资金到可用余额
                boolean success = merchantAccountService.releaseFrozenToAvailable(merchantUserId, revenueAmount);

                if (success) {
                    markRevenueAsSettled(detailIds);
                    log.info("成功更新商家 {} 的账户余额", merchantUserId);
                } else {
                    log.warn("更新商家 {} 的账户余额失败", merchantUserId);
                }
            } catch (Exception e) {
                log.error("更新商家 {} 的账户余额时发生异常", merchantUserId, e);
            }
        });
        return true;
    }

}