package com.yolo.keyboard.job;

import cn.hutool.core.collection.CollUtil;
import com.yolo.keyboard.dal.dataobject.tenantbalance.TenantBalanceDO;
import com.yolo.keyboard.dal.dataobject.tenantbalancetransaction.TenantBalanceTransactionDO;
import com.yolo.keyboard.dal.dataobject.tenantcommission.KeyboardTenantCommissionDO;
import com.yolo.keyboard.dal.dataobject.userinvites.KeyboardUserInvitesDO;
import com.yolo.keyboard.dal.dataobject.userpurchaserecords.KeyboardUserPurchaseRecordsDO;
import com.yolo.keyboard.dal.mysql.tenantbalance.TenantBalanceMapper;
import com.yolo.keyboard.dal.mysql.tenantbalancetransaction.TenantBalanceTransactionMapper;
import com.yolo.keyboard.dal.mysql.tenantcommission.KeyboardTenantCommissionMapper;
import com.yolo.keyboard.dal.mysql.userinvites.KeyboardUserInvitesMapper;
import com.yolo.keyboard.dal.mysql.userpurchaserecords.KeyboardUserPurchaseRecordsMapper;
import com.yolo.keyboard.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.yolo.keyboard.framework.quartz.core.handler.JobHandler;
import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore;
import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantDO;
import com.yolo.keyboard.module.system.dal.mysql.tenant.TenantMapper;
import com.yolo.keyboard.utils.BizNoGenerator;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 租户分成计算定时任务
 * 每小时执行一次，计算邀请用户的内购分成
 * 支持一级代理和二级代理的分成计算
 *
 * @author ziin
 */
@Component
@Slf4j
public class TenantCommissionCalculateJob implements JobHandler {

    @Resource
    private KeyboardUserPurchaseRecordsMapper purchaseRecordsMapper;

    @Resource
    private KeyboardUserInvitesMapper userInvitesMapper;

    @Resource
    private KeyboardTenantCommissionMapper commissionMapper;

    @Resource
    private TenantMapper tenantMapper;

    @Resource
    private TenantBalanceMapper tenantBalanceMapper;

    @Resource
    private TenantBalanceTransactionMapper balanceTransactionMapper;

    private static final String COMMISSION_TYPE = "COMMISSION";
    private static final String STATUS_PAID = "PAID";
    private static final String INVITE_TYPE_AGENT = "AGENT";

    @Override
    @TenantIgnore
    @Transactional(rollbackFor = Exception.class)
    public String execute(String param) {
        log.info("[TenantCommissionCalculateJob] 开始执行分成计算任务");

        // 1. 查询最近一小时内已支付的内购记录
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusHours(1);

        List<KeyboardUserPurchaseRecordsDO> purchaseRecords = purchaseRecordsMapper.selectList(
                new LambdaQueryWrapperX<KeyboardUserPurchaseRecordsDO>()
                        .eq(KeyboardUserPurchaseRecordsDO::getStatus, STATUS_PAID)
                        .between(KeyboardUserPurchaseRecordsDO::getPurchaseTime, startTime, endTime)
        );

        if (CollUtil.isEmpty(purchaseRecords)) {
            log.info("[TenantCommissionCalculateJob] 最近一小时内没有已支付的内购记录");
            return "没有需要处理的内购记录";
        }

        int processedCount = 0;
        int commissionCount = 0;
        BigDecimal totalCommission = BigDecimal.ZERO;

        // 2. 遍历内购记录，检查是否有邀请关系
        for (KeyboardUserPurchaseRecordsDO record : purchaseRecords) {
            // 检查是否已经计算过分成
            if (commissionMapper.selectByPurchaseRecordId(record.getId()) != null) {
                log.debug("[TenantCommissionCalculateJob] 内购记录 {} 已计算过分成，跳过", record.getId());
                continue;
            }

            processedCount++;

            // 查询该用户的邀请关系
            KeyboardUserInvitesDO invite = userInvitesMapper.selectOne(
                    KeyboardUserInvitesDO::getInviteeUserId, record.getUserId().longValue()
            );

            if (invite == null) {
                log.debug("[TenantCommissionCalculateJob] 用户 {} 没有邀请关系，跳过", record.getUserId());
                continue;
            }

            // 只处理代理邀请类型
            if (!INVITE_TYPE_AGENT.equals(invite.getInviteType())) {
                log.debug("[TenantCommissionCalculateJob] 用户 {} 的邀请类型不是代理，跳过", record.getUserId());
                continue;
            }

            // 获取收益归属租户（邀请人所属租户）
            Long inviterTenantId = invite.getProfitTenantId();
            if (inviterTenantId == null) {
                inviterTenantId = invite.getInviterTenantId();
            }
            if (inviterTenantId == null) {
                log.warn("[TenantCommissionCalculateJob] 用户 {} 的邀请关系没有关联租户，跳过", record.getUserId());
                continue;
            }

            // 获取邀请人租户信息
            TenantDO inviterTenant = tenantMapper.selectById(inviterTenantId);
            if (inviterTenant == null) {
                log.warn("[TenantCommissionCalculateJob] 租户 {} 不存在，跳过", inviterTenantId);
                continue;
            }

            // 获取内购金额
            BigDecimal purchaseAmount = record.getPrice();
            if (purchaseAmount == null || purchaseAmount.compareTo(BigDecimal.ZERO) <= 0) {
                log.debug("[TenantCommissionCalculateJob] 内购记录 {} 金额无效，跳过", record.getId());
                continue;
            }

            LocalDateTime now = LocalDateTime.now();
            LocalDateTime withdrawableAt = now.plusDays(30);

            // 判断是否是二级代理（有上级租户）
            if (inviterTenant.getParentId() != null) {
                // 二级代理场景：需要给一级代理和二级代理都分成
                TenantDO parentTenant = tenantMapper.selectById(inviterTenant.getParentId());
                if (parentTenant == null) {
                    log.warn("[TenantCommissionCalculateJob] 上级租户 {} 不存在，跳过", inviterTenant.getParentId());
                    continue;
                }

                // 使用一级代理的分成比例计算总分成
                BigDecimal totalCommissionRate = parentTenant.getProfitShareRatio();
                if (totalCommissionRate == null || totalCommissionRate.compareTo(BigDecimal.ZERO) <= 0) {
                    log.debug("[TenantCommissionCalculateJob] 一级代理租户 {} 没有设置分成比例，跳过", parentTenant.getId());
                    continue;
                }

                BigDecimal totalCommissionAmount = purchaseAmount.multiply(totalCommissionRate)
                        .setScale(2, RoundingMode.HALF_UP);

                // 获取二级代理的返点比例
                BigDecimal rebateRatio = inviterTenant.getUpstreamRebateRatio();
                if (rebateRatio == null || rebateRatio.compareTo(BigDecimal.ZERO) <= 0) {
                    // 如果没有设置返点比例，全部归一级代理
                    log.debug("[TenantCommissionCalculateJob] 二级代理租户 {} 没有设置返点比例，全部归一级代理", inviterTenantId);
                    int count = createCommissionRecord(record, invite, parentTenant.getId(), purchaseAmount,
                            totalCommissionRate, totalCommissionAmount, now, withdrawableAt,
                            "一级代理分成（二级代理无返点）");
                    commissionCount += count;
                    totalCommission = totalCommission.add(totalCommissionAmount);
                } else {
                    // 计算二级代理分成
                    BigDecimal secondLevelAmount = totalCommissionAmount.multiply(rebateRatio)
                            .setScale(2, RoundingMode.HALF_UP);
                    // 计算一级代理分成
                    BigDecimal firstLevelAmount = totalCommissionAmount.subtract(secondLevelAmount);

                    // 为二级代理创建分成记录
                    if (secondLevelAmount.compareTo(BigDecimal.ZERO) > 0) {
                        int count = createCommissionRecord(record, invite, inviterTenantId, purchaseAmount,
                                rebateRatio, secondLevelAmount, now, withdrawableAt,
                                "二级代理分成");
                        commissionCount += count;
                        totalCommission = totalCommission.add(secondLevelAmount);
                        log.info("[TenantCommissionCalculateJob] 内购记录 {}, 二级代理 {}, 分成金额 {}",
                                record.getId(), inviterTenantId, secondLevelAmount);
                    }

                    // 为一级代理创建分成记录
                    if (firstLevelAmount.compareTo(BigDecimal.ZERO) > 0) {
                        BigDecimal firstLevelRate = BigDecimal.ONE.subtract(rebateRatio);
                        int count = createCommissionRecord(record, invite, parentTenant.getId(), purchaseAmount,
                                firstLevelRate, firstLevelAmount, now, withdrawableAt,
                                "一级代理分成（扣除二级返点）");
                        commissionCount += count;
                        totalCommission = totalCommission.add(firstLevelAmount);
                        log.info("[TenantCommissionCalculateJob] 内购记录 {}, 一级代理 {}, 分成金额 {}",
                                record.getId(), parentTenant.getId(), firstLevelAmount);
                    }
                }
            } else {
                // 一级代理场景：全部分成归一级代理
                BigDecimal commissionRate = inviterTenant.getProfitShareRatio();
                if (commissionRate == null || commissionRate.compareTo(BigDecimal.ZERO) <= 0) {
                    log.debug("[TenantCommissionCalculateJob] 租户 {} 没有设置分成比例，跳过", inviterTenantId);
                    continue;
                }

                BigDecimal commissionAmount = purchaseAmount.multiply(commissionRate)
                        .setScale(2, RoundingMode.HALF_UP);

                int count = createCommissionRecord(record, invite, inviterTenantId, purchaseAmount,
                        commissionRate, commissionAmount, now, withdrawableAt,
                        "一级代理分成");
                commissionCount += count;
                totalCommission = totalCommission.add(commissionAmount);

                log.info("[TenantCommissionCalculateJob] 内购记录 {}, 一级代理 {}, 分成金额 {}",
                        record.getId(), inviterTenantId, commissionAmount);
            }
        }

        String result = String.format("处理内购记录 %d 条，生成分成 %d 条，总分成金额 %s",
                processedCount, commissionCount, totalCommission.toPlainString());
        log.info("[TenantCommissionCalculateJob] 任务执行完成: {}", result);
        return result;
    }

    /**
     * 创建分成记录并更新租户余额
     *
     * @return 创建的分成记录数量
     */
    private int createCommissionRecord(KeyboardUserPurchaseRecordsDO record,
                                       KeyboardUserInvitesDO invite,
                                       Long tenantId,
                                       BigDecimal purchaseAmount,
                                       BigDecimal commissionRate,
                                       BigDecimal commissionAmount,
                                       LocalDateTime now,
                                       LocalDateTime withdrawableAt,
                                       String remark) {
        // 0. 检查该租户是否已对该内购记录计算过分成（防止重复计算）
        KeyboardTenantCommissionDO existingCommission = commissionMapper.selectByPurchaseRecordIdAndTenantId(record.getId(), tenantId);
        if (existingCommission != null) {
            log.debug("[TenantCommissionCalculateJob] 租户 {} 已对内购记录 {} 计算过分成，跳过", tenantId, record.getId());
            return 0;
        }

        // 1. 创建分成记录
        KeyboardTenantCommissionDO commission = KeyboardTenantCommissionDO.builder()
                .purchaseRecordId(record.getId())
                .transactionId(record.getTransactionId())
                .inviteeUserId(record.getUserId())
                .inviterUserId(invite.getProfitEmployeeId())
                .tenantId(tenantId)
                .purchaseAmount(purchaseAmount)
                .commissionRate(commissionRate)
                .commissionAmount(commissionAmount)
                .status("SETTLED")
                .purchaseTime(record.getPurchaseTime())
                .settledAt(now)
                .withdrawableAt(withdrawableAt)
                .withdrawableProcessed(false)
                .createdAt(now)
                .updatedAt(now)
                .remark(remark)
                .build();

        // 2. 更新租户余额（分成金额先计入总余额，30天后才可提现）
        TenantBalanceDO balance = tenantBalanceMapper.selectById(tenantId);
        if (balance == null) {
            balance = new TenantBalanceDO();
            balance.setId(tenantId);
            balance.setBalance(commissionAmount);
            balance.setWithdrawableBalance(BigDecimal.ZERO);
            balance.setFrozenAmt(BigDecimal.ZERO);
            balance.setVersion(0);
            tenantBalanceMapper.insert(balance);
        } else {
            BigDecimal newBalance = balance.getBalance().add(commissionAmount);
            balance.setBalance(newBalance);
            tenantBalanceMapper.updateById(balance);
        }

        // 3. 创建余额交易记录
        String bizNo = BizNoGenerator.generate("COMM");
        TenantBalanceTransactionDO transaction = TenantBalanceTransactionDO.builder()
                .bizNo(bizNo)
                .points(commissionAmount)
                .balance(balance.getBalance())
                .frozenAmt(balance.getFrozenAmt() != null ? balance.getFrozenAmt() : BigDecimal.ZERO)
                .withdrawableBalance(balance.getWithdrawableBalance() != null ? balance.getWithdrawableBalance() : BigDecimal.ZERO)
                .tenantId(tenantId)
                .type(COMMISSION_TYPE)
                .description("邀请用户内购分成")
                .orderId(record.getTransactionId())
                .createdAt(now)
                .remark("内购记录ID: " + record.getId() + ", 被邀请用户: " + record.getUserId() + ", " + remark)
                .build();
        balanceTransactionMapper.insert(transaction);

        // 4. 更新分成记录的关联交易ID并保存
        commission.setBalanceTransactionId(transaction.getId());
        commissionMapper.insert(commission);

        return 1;
    }
}
