package com.starry.admin.modules.withdraw.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starry.admin.modules.order.module.constant.OrderConstant;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.withdraw.entity.EarningsLineEntity;
import com.starry.admin.modules.withdraw.enums.EarningsType;
import com.starry.admin.modules.withdraw.mapper.EarningsLineMapper;
import com.starry.admin.modules.withdraw.service.IEarningsService;
import com.starry.admin.modules.withdraw.service.IFreezePolicyService;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class EarningsServiceImpl extends ServiceImpl<EarningsLineMapper, EarningsLineEntity>
        implements IEarningsService {

    @Resource
    private IFreezePolicyService freezePolicyService;

    @Override
    public void createFromOrder(PlayOrderInfoEntity orderInfo) {
        if (orderInfo == null || orderInfo.getAcceptBy() == null) return;
        if (OrderConstant.OrderType.BLIND_BOX_PURCHASE.getCode().equals(orderInfo.getOrderType())) {
            return;
        }
        // amount from estimatedRevenue; fallback to orderMoney if null
        BigDecimal amount = orderInfo.getEstimatedRevenue() != null ? orderInfo.getEstimatedRevenue()
                : (orderInfo.getOrderMoney() != null ? orderInfo.getOrderMoney() : BigDecimal.ZERO);
        if (amount.compareTo(BigDecimal.ZERO) < 0) return;

        int freezeHours = freezePolicyService
                .resolveFreezeHours(orderInfo.getTenantId(), orderInfo.getAcceptBy());
        LocalDateTime endTime = orderInfo.getOrderEndTime();
        if (endTime == null) return;
        LocalDateTime unlockTime = endTime.plusHours(freezeHours);
        LocalDateTime now = LocalDateTime.now();

        EarningsLineEntity line = new EarningsLineEntity();
        line.setId(IdUtils.getUuid());
        line.setTenantId(orderInfo.getTenantId());
        line.setClerkId(orderInfo.getAcceptBy());
        line.setOrderId(orderInfo.getId());
        line.setAmount(amount);
        line.setEarningType(EarningsType.ORDER);
        line.setUnlockTime(unlockTime);
        line.setStatus(unlockTime.isAfter(now) ? "frozen" : "available");
        this.save(line);
    }

    @Override
    public BigDecimal getAvailableAmount(String clerkId, LocalDateTime now) {
        // available = sum(frozen where unlock<=now) + sum(available)
        BigDecimal sum = this.baseMapper.sumWithdrawableAmount(clerkId, now);
        return sum == null ? BigDecimal.ZERO : sum;
    }

    @Override
    public BigDecimal getPendingAmount(String clerkId, LocalDateTime now) {
        // pending = sum(frozen where unlock>now)
        BigDecimal sum = this.baseMapper.sumPendingAmount(clerkId, now);
        return sum == null ? BigDecimal.ZERO : sum;
    }

    @Override
    public LocalDateTime getNextUnlockTime(String clerkId, LocalDateTime now) {
        LambdaQueryWrapper<EarningsLineEntity> q = new LambdaQueryWrapper<>();
        q.eq(EarningsLineEntity::getClerkId, clerkId)
                .eq(EarningsLineEntity::getStatus, "frozen")
                .gt(EarningsLineEntity::getUnlockTime, now)
                .orderByAsc(EarningsLineEntity::getUnlockTime)
                .last("limit 1");
        EarningsLineEntity line = this.baseMapper.selectOne(q);
        return line == null ? null : line.getUnlockTime();
    }

    @Override
    public List<EarningsLineEntity> findWithdrawable(String clerkId, BigDecimal amount, LocalDateTime now) {
        // pick oldest unlocked first (status in available or frozen with unlock<=now)
        List<EarningsLineEntity> list = this.baseMapper.selectWithdrawableLines(clerkId, now);
        BigDecimal acc = BigDecimal.ZERO;
        List<EarningsLineEntity> picked = new ArrayList<>();
        for (EarningsLineEntity e : list) {
            picked.add(e);
            acc = acc.add(e.getAmount());
            if (acc.compareTo(amount) >= 0) break;
        }
        if (acc.compareTo(amount) < 0) return new ArrayList<>();
        return picked;
    }

    @Override
    public void createCounterLine(String orderId, String tenantId, String targetClerkId, BigDecimal amount, String operatorId) {
        if (StrUtil.hasBlank(orderId, tenantId, targetClerkId)) {
            throw new IllegalArgumentException("创建冲销收益时参数缺失");
        }
        BigDecimal normalized = amount == null ? BigDecimal.ZERO : amount.abs();
        if (normalized.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime resolvedUnlock = now;
        String resolvedStatus = "available";

        List<EarningsLineEntity> references = this.baseMapper.selectList(new LambdaQueryWrapper<EarningsLineEntity>()
                .eq(EarningsLineEntity::getOrderId, orderId)
                .eq(EarningsLineEntity::getClerkId, targetClerkId)
                .eq(EarningsLineEntity::getDeleted, false)
                .orderByAsc(EarningsLineEntity::getUnlockTime));
        EarningsLineEntity reference = references.stream()
                .filter(line -> line.getAmount() != null && line.getAmount().compareTo(BigDecimal.ZERO) > 0)
                .findFirst()
                .orElse(null);
        if (reference == null) {
            throw new IllegalStateException("未找到可冲销的收益记录");
        }
        LocalDateTime refUnlock = reference.getUnlockTime();
        String refStatus = reference.getStatus();
        boolean shouldPreserveFreeze = "frozen".equalsIgnoreCase(refStatus)
                && refUnlock != null
                && refUnlock.isAfter(now);
        if (shouldPreserveFreeze) {
            resolvedUnlock = refUnlock;
            resolvedStatus = "frozen";
        } else {
            resolvedUnlock = now;
            resolvedStatus = "available";
        }

        EarningsLineEntity line = new EarningsLineEntity();
        line.setId(IdUtils.getUuid());
        line.setOrderId(orderId);
        line.setTenantId(tenantId);
        line.setClerkId(targetClerkId);
        line.setAmount(normalized.negate());
        line.setEarningType(EarningsType.ADJUSTMENT);
        line.setStatus(resolvedStatus);
        line.setUnlockTime(resolvedUnlock);
        this.save(line);
    }

    @Override
    public BigDecimal getRemainingEarningsForOrder(String orderId, String clerkId) {
        if (StrUtil.hasBlank(orderId, clerkId)) {
            return BigDecimal.ZERO;
        }
        List<EarningsLineEntity> lines = this.lambdaQuery()
                .eq(EarningsLineEntity::getOrderId, orderId)
                .eq(EarningsLineEntity::getClerkId, clerkId)
                .eq(EarningsLineEntity::getDeleted, false)
                .list();
        BigDecimal total = BigDecimal.ZERO;
        for (EarningsLineEntity line : lines) {
            BigDecimal amount = line.getAmount() == null ? BigDecimal.ZERO : line.getAmount();
            total = total.add(amount);
        }
        return total;
    }

}
