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 tenantId = invite.getProfitTenantId();
            if (tenantId == null) {
                tenantId = invite.getInviterTenantId();
            }
            if (tenantId == null) {
                log.warn("[TenantCommissionCalculateJob] 用户 {} 的邀请关系没有关联租户，跳过", record.getUserId());
                continue;
            }

            // 获取租户信息和分成比例
            TenantDO tenant = tenantMapper.selectById(tenantId);
            if (tenant == null) {
                log.warn("[TenantCommissionCalculateJob] 租户 {} 不存在，跳过", tenantId);
                continue;
            }

            BigDecimal commissionRate = tenant.getProfitShareRatio();
            if (commissionRate == null || commissionRate.compareTo(BigDecimal.ZERO) <= 0) {
                log.debug("[TenantCommissionCalculateJob] 租户 {} 没有设置分成比例，跳过", tenantId);
                continue;
            }

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

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

            // 4. 创建分成记录
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime withdrawableAt = now.plusDays(30); // 30天后可提现
            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)
                    .build();

            // 5. 更新租户余额（分成金额先计入总余额，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);
            }

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

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

            commissionCount++;
            totalCommission = totalCommission.add(commissionAmount);

            log.info("[TenantCommissionCalculateJob] 处理内购记录 {}, 租户 {}, 分成金额 {}",
                    record.getId(), tenantId, commissionAmount);
        }

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