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.DistributorWithdrawalStatus;
import com.haha.common.exception.BusinessException;
import com.haha.common.vo.StatusLabel;
import com.haha.entity.Distributor;
import com.haha.entity.DistributorWithdrawal;
import com.haha.entity.dto.WithdrawalQueryDTO;
import com.haha.entity.dto.WithdrawalReviewDTO;
import com.haha.mapper.DistributorMapper;
import com.haha.mapper.DistributorWithdrawalMapper;
import com.haha.service.DistributorConfigService;
import com.haha.service.DistributorWithdrawalService;
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;

@Slf4j
@Service
@RequiredArgsConstructor
public class DistributorWithdrawalServiceImpl extends ServiceImpl<DistributorWithdrawalMapper, DistributorWithdrawal> implements DistributorWithdrawalService {

    private final DistributorWithdrawalMapper withdrawalMapper;
    private final DistributorMapper distributorMapper;
    private final DistributorConfigService configService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DistributorWithdrawal applyWithdrawal(Long distributorId, BigDecimal amount) {
        Distributor distributor = distributorMapper.selectById(distributorId);
        if (distributor == null) {
            throw new BusinessException(404, "分销员不存在");
        }

        BigDecimal minWithdrawalAmount = configService.getMinWithdrawalAmount();
        if (amount.compareTo(minWithdrawalAmount) < 0) {
            throw new BusinessException(400, "提现金额不能低于最低提现金额" + minWithdrawalAmount);
        }

        if (amount.compareTo(distributor.getCommissionBalance()) > 0) {
            throw new BusinessException(400, "提现金额不能超过可提现余额");
        }

        distributorMapper.freezeAmount(distributorId, amount);

        DistributorWithdrawal withdrawal = new DistributorWithdrawal();
        withdrawal.setDistributorId(distributorId);
        withdrawal.setAmount(amount);
        withdrawal.setStatus(DistributorWithdrawalStatus.PENDING.getCode());
        withdrawal.setCreateTime(LocalDateTime.now());
        withdrawal.setUpdateTime(LocalDateTime.now());

        this.save(withdrawal);

        log.info("[提现] 申请成功 - id: {}, distributorId: {}, amount: {}", withdrawal.getId(), distributorId, amount);
        return withdrawal;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DistributorWithdrawal reviewWithdrawal(WithdrawalReviewDTO dto, Long reviewerId, String reviewerName) {
        DistributorWithdrawal withdrawal = this.getById(dto.getId());
        if (withdrawal == null) {
            throw new BusinessException(404, "提现申请不存在");
        }

        if (withdrawal.getStatus() != DistributorWithdrawalStatus.PENDING.getCode()) {
            throw new BusinessException(400, "该申请已处理");
        }

        withdrawal.setReviewerId(reviewerId);
        withdrawal.setReviewerName(reviewerName);
        withdrawal.setReviewTime(LocalDateTime.now());
        withdrawal.setReviewRemark(dto.getReviewRemark());

        if (dto.getStatus() == DistributorWithdrawalStatus.APPROVED.getCode()) {
            withdrawal.setStatus(DistributorWithdrawalStatus.APPROVED.getCode());
        } else if (dto.getStatus() == DistributorWithdrawalStatus.REJECTED.getCode()) {
            withdrawal.setStatus(DistributorWithdrawalStatus.REJECTED.getCode());
            distributorMapper.unfreezeAmount(withdrawal.getDistributorId(), withdrawal.getAmount());
        }

        withdrawal.setUpdateTime(LocalDateTime.now());
        this.updateById(withdrawal);

        log.info("[提现] 审核完成 - id: {}, status: {}", withdrawal.getId(), dto.getStatus());
        return withdrawal;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DistributorWithdrawal confirmTransfer(Long withdrawalId) {
        DistributorWithdrawal withdrawal = this.getById(withdrawalId);
        if (withdrawal == null) {
            throw new BusinessException(404, "提现申请不存在");
        }

        if (withdrawal.getStatus() != DistributorWithdrawalStatus.APPROVED.getCode()) {
            throw new BusinessException(400, "提现申请未通过审核");
        }

        withdrawal.setStatus(DistributorWithdrawalStatus.COMPLETED.getCode());
        withdrawal.setTransferTime(LocalDateTime.now());
        withdrawal.setUpdateTime(LocalDateTime.now());

        distributorMapper.deductWithdrawal(withdrawal.getDistributorId(), withdrawal.getAmount());

        this.updateById(withdrawal);

        log.info("[提现] 确认到账 - id: {}, distributorId: {}, amount: {}", withdrawal.getId(), withdrawal.getDistributorId(), withdrawal.getAmount());
        return withdrawal;
    }

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

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

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

        return result;
    }

    private void fillLabels(DistributorWithdrawal withdrawal) {
        if (withdrawal == null) {
            return;
        }

        if (withdrawal.getStatus() != null) {
            StatusLabel statusLabel = DistributorWithdrawalStatus.getLabelByCode(withdrawal.getStatus());
            if (statusLabel != null) {
                withdrawal.setStatusLabel(statusLabel.getLabel());
            }
        }

        if (withdrawal.getDistributorId() != null) {
            Distributor distributor = distributorMapper.selectById(withdrawal.getDistributorId());
            if (distributor != null) {
                withdrawal.setDistributorName(distributor.getName());
            }
        }
    }
}
