package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.enums.DistributorCommissionStatus;
import com.haha.common.enums.DistributorReferralStatus;
import com.haha.common.vo.StatusLabel;
import com.haha.entity.Distributor;
import com.haha.entity.DistributorCommission;
import com.haha.entity.DistributorReferral;
import com.haha.entity.User;
import com.haha.entity.dto.CommissionQueryDTO;
import com.haha.mapper.DistributorCommissionMapper;
import com.haha.mapper.DistributorMapper;
import com.haha.mapper.UserMapper;
import com.haha.service.DistributorCommissionService;
import com.haha.service.DistributorConfigService;
import com.haha.service.DistributorReferralService;
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.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class DistributorCommissionServiceImpl extends ServiceImpl<DistributorCommissionMapper, DistributorCommission> implements DistributorCommissionService {

    private final DistributorCommissionMapper commissionMapper;
    private final DistributorReferralService referralService;
    private final DistributorConfigService configService;
    private final DistributorMapper distributorMapper;
    private final UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processOrderCommission(Long userId, Long orderId, BigDecimal orderAmount) {
        DistributorReferral referral = referralService.getByUserId(userId);
        if (referral == null) {
            return;
        }
        if (referral.getStatus() != DistributorReferralStatus.PENDING.getCode()) {
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        if (referral.getExpireTime() != null && now.isAfter(referral.getExpireTime())) {
            referral.setStatus(DistributorReferralStatus.EXPIRED.getCode());
            referral.setUpdateTime(now);
            referralService.updateById(referral);
            return;
        }
        String validUserRule = configService.getValidUserRule();
        boolean isValidUser = false;
        switch (validUserRule) {
            case "FIRST_ORDER":
                isValidUser = true;
                break;
            case "MIN_AMOUNT":
                BigDecimal minAmount = configService.getMinValidOrderAmount();
                isValidUser = orderAmount.compareTo(minAmount) >= 0;
                break;
            case "BOTH":
                BigDecimal minAmountBoth = configService.getMinValidOrderAmount();
                isValidUser = orderAmount.compareTo(minAmountBoth) >= 0;
                break;
            default:
                isValidUser = true;
        }
        if (isValidUser) {
            referral.setStatus(DistributorReferralStatus.ACTIVE.getCode());
            referral.setFirstOrderId(orderId);
            referral.setFirstOrderAmount(orderAmount);
            referral.setFirstOrderTime(now);
            referral.setEffectiveTime(now);
            referral.setUpdateTime(now);
            referralService.updateById(referral);
            distributorMapper.incrementValidReferrals(referral.getDistributorId());
            calculateCommission(referral, orderAmount);
        } else {
            referral.setFirstOrderId(orderId);
            referral.setFirstOrderAmount(orderAmount);
            referral.setFirstOrderTime(now);
            referral.setUpdateTime(now);
            referralService.updateById(referral);
        }
    }

    private void calculateCommission(DistributorReferral referral, BigDecimal orderAmount) {
        List<DistributorCommission> commissions = new ArrayList<>();
        BigDecimal fixedCommissionAmount = configService.getFixedCommissionAmount();
        if (fixedCommissionAmount.compareTo(BigDecimal.ZERO) > 0) {
            DistributorCommission fixedCommission = new DistributorCommission();
            fixedCommission.setDistributorId(referral.getDistributorId());
            fixedCommission.setReferralId(referral.getId());
            fixedCommission.setUserId(referral.getUserId());
            fixedCommission.setCommissionType(0);
            fixedCommission.setAmount(fixedCommissionAmount);
            fixedCommission.setOrderAmount(null);
            fixedCommission.setRate(null);
            fixedCommission.setStatus(DistributorCommissionStatus.PENDING.getCode());
            fixedCommission.setCreateTime(LocalDateTime.now());
            commissions.add(fixedCommission);
        }
        BigDecimal firstOrderCommissionRate = configService.getFirstOrderCommissionRate();
        if (firstOrderCommissionRate.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal commissionAmount = orderAmount.multiply(firstOrderCommissionRate)
                    .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
            if (commissionAmount.compareTo(new BigDecimal("0.01")) < 0) {
                commissionAmount = new BigDecimal("0.01");
            }
            DistributorCommission rateCommission = new DistributorCommission();
            rateCommission.setDistributorId(referral.getDistributorId());
            rateCommission.setReferralId(referral.getId());
            rateCommission.setUserId(referral.getUserId());
            rateCommission.setCommissionType(1);
            rateCommission.setAmount(commissionAmount);
            rateCommission.setOrderAmount(orderAmount);
            rateCommission.setRate(firstOrderCommissionRate);
            rateCommission.setStatus(DistributorCommissionStatus.PENDING.getCode());
            rateCommission.setCreateTime(LocalDateTime.now());
            commissions.add(rateCommission);
        }
        if (!commissions.isEmpty()) {
            this.saveBatch(commissions);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal settleCommissions(Long distributorId, String yearMonth) {
        BigDecimal sum = commissionMapper.sumPendingCommissionByMonth(distributorId, yearMonth);
        if (sum.compareTo(BigDecimal.ZERO) > 0) {
            commissionMapper.settleByMonth(distributorId, yearMonth);
            distributorMapper.addCommissionBalance(distributorId, sum);
        }
        return sum;
    }

    @Override
    public IPage<DistributorCommission> getPage(CommissionQueryDTO queryDTO) {
        queryDTO.validate();
        Page<DistributorCommission> page = new Page<>(queryDTO.getPage(), queryDTO.getPageSize());

        LambdaQueryWrapper<DistributorCommission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(queryDTO.getDistributorId() != null, DistributorCommission::getDistributorId, queryDTO.getDistributorId());
        wrapper.eq(queryDTO.getUserId() != null, DistributorCommission::getUserId, queryDTO.getUserId());
        wrapper.eq(queryDTO.getCommissionType() != null, DistributorCommission::getCommissionType, queryDTO.getCommissionType());
        wrapper.eq(queryDTO.getStatus() != null, DistributorCommission::getStatus, queryDTO.getStatus());
        if (queryDTO.getStartDate() != null) {
            wrapper.ge(DistributorCommission::getCreateTime, queryDTO.getStartDate());
        }
        if (queryDTO.getEndDate() != null) {
            wrapper.le(DistributorCommission::getCreateTime, queryDTO.getEndDate() + " 23:59:59");
        }
        wrapper.orderByDesc(DistributorCommission::getCreateTime);

        IPage<DistributorCommission> result = this.page(page, wrapper);
        result.getRecords().forEach(this::fillLabels);

        return result;
    }

    private void fillLabels(DistributorCommission commission) {
        if (commission == null) {
            return;
        }
        if (commission.getCommissionType() != null) {
            switch (commission.getCommissionType()) {
                case 0:
                    commission.setCommissionTypeLabel("拉新奖励");
                    break;
                case 1:
                    commission.setCommissionTypeLabel("消费提成");
                    break;
                default:
                    commission.setCommissionTypeLabel("未知");
            }
        }
        if (commission.getStatus() != null) {
            StatusLabel statusLabel = DistributorCommissionStatus.getLabelByCode(commission.getStatus());
            commission.setStatusLabel(statusLabel.getLabel());
        }
        if (commission.getDistributorId() != null) {
            Distributor distributor = distributorMapper.selectById(commission.getDistributorId());
            if (distributor != null) {
                commission.setDistributorName(distributor.getName());
            }
        }
        if (commission.getUserId() != null) {
            User user = userMapper.selectById(commission.getUserId());
            if (user != null) {
                commission.setUserName(user.getNickname());
            } else {
                commission.setUserName("未知用户");
            }
        }
    }
}
