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.constant.CommonConstants;
import com.haha.common.enums.DistributorCommissionStatus;
import com.haha.common.enums.DistributorReferralStatus;
import com.haha.common.enums.DistributorStatus;
import com.haha.common.exception.BusinessException;
import com.haha.entity.Distributor;
import com.haha.entity.DistributorCommission;
import com.haha.entity.DistributorMonthlyReport;
import com.haha.entity.DistributorReferral;
import com.haha.entity.dto.MonthlyReportQueryDTO;
import com.haha.entity.vo.DistributorDashboardVO;
import com.haha.entity.vo.MonthlyTrendVO;
import com.haha.mapper.DistributorCommissionMapper;
import com.haha.mapper.DistributorMapper;
import com.haha.mapper.DistributorMonthlyReportMapper;
import com.haha.mapper.DistributorReferralMapper;
import com.haha.service.DistributorCommissionService;
import com.haha.service.DistributorReportService;
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;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class DistributorReportServiceImpl extends ServiceImpl<DistributorMonthlyReportMapper, DistributorMonthlyReport> implements DistributorReportService {

    private final DistributorMonthlyReportMapper reportMapper;
    private final DistributorMapper distributorMapper;
    private final DistributorReferralMapper referralMapper;
    private final DistributorCommissionMapper commissionMapper;
    private final DistributorCommissionService commissionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateMonthlyReport(String yearMonth) {
        LambdaQueryWrapper<Distributor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Distributor::getStatus, DistributorStatus.ACTIVE.getCode());
        wrapper.eq(Distributor::getDeleted, CommonConstants.NOT_DELETED);
        List<Distributor> distributors = distributorMapper.selectList(wrapper);

        for (Distributor distributor : distributors) {
            generateDistributorMonthlyReport(distributor.getId(), yearMonth);
            commissionService.settleCommissions(distributor.getId(), yearMonth);
        }

        log.info("[月度报表] 生成完成 - yearMonth: {}, 处理分销员数量: {}", yearMonth, distributors.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DistributorMonthlyReport generateDistributorMonthlyReport(Long distributorId, String yearMonth) {
        LambdaQueryWrapper<DistributorMonthlyReport> existWrapper = new LambdaQueryWrapper<>();
        existWrapper.eq(DistributorMonthlyReport::getDistributorId, distributorId);
        existWrapper.eq(DistributorMonthlyReport::getYearMonth, yearMonth);
        DistributorMonthlyReport report = reportMapper.selectOne(existWrapper);

        if (report == null) {
            report = new DistributorMonthlyReport();
            report.setDistributorId(distributorId);
            report.setYearMonth(yearMonth);
            report.setCreateTime(LocalDateTime.now());
        }

        LambdaQueryWrapper<DistributorReferral> totalReferralWrapper = new LambdaQueryWrapper<>();
        totalReferralWrapper.eq(DistributorReferral::getDistributorId, distributorId);
        totalReferralWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", yearMonth);
        Long totalReferrals = referralMapper.selectCount(totalReferralWrapper);

        LambdaQueryWrapper<DistributorReferral> validReferralWrapper = new LambdaQueryWrapper<>();
        validReferralWrapper.eq(DistributorReferral::getDistributorId, distributorId);
        validReferralWrapper.eq(DistributorReferral::getStatus, DistributorReferralStatus.ACTIVE.getCode());
        validReferralWrapper.apply("DATE_FORMAT(effective_time, '%Y-%m') = {0}", yearMonth);
        Long validReferrals = referralMapper.selectCount(validReferralWrapper);

        LambdaQueryWrapper<DistributorReferral> pendingReferralWrapper = new LambdaQueryWrapper<>();
        pendingReferralWrapper.eq(DistributorReferral::getDistributorId, distributorId);
        pendingReferralWrapper.eq(DistributorReferral::getStatus, DistributorReferralStatus.PENDING.getCode());
        pendingReferralWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", yearMonth);
        Long pendingReferrals = referralMapper.selectCount(pendingReferralWrapper);

        LambdaQueryWrapper<DistributorReferral> expiredReferralWrapper = new LambdaQueryWrapper<>();
        expiredReferralWrapper.eq(DistributorReferral::getDistributorId, distributorId);
        expiredReferralWrapper.eq(DistributorReferral::getStatus, DistributorReferralStatus.EXPIRED.getCode());
        expiredReferralWrapper.apply("DATE_FORMAT(update_time, '%Y-%m') = {0}", yearMonth);
        Long expiredReferrals = referralMapper.selectCount(expiredReferralWrapper);

        LambdaQueryWrapper<DistributorCommission> totalCommissionWrapper = new LambdaQueryWrapper<>();
        totalCommissionWrapper.eq(DistributorCommission::getDistributorId, distributorId);
        totalCommissionWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", yearMonth);
        List<DistributorCommission> totalCommissions = commissionMapper.selectList(totalCommissionWrapper);
        BigDecimal totalCommission = totalCommissions.stream()
                .map(DistributorCommission::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        LambdaQueryWrapper<DistributorCommission> settledCommissionWrapper = new LambdaQueryWrapper<>();
        settledCommissionWrapper.eq(DistributorCommission::getDistributorId, distributorId);
        settledCommissionWrapper.eq(DistributorCommission::getStatus, DistributorCommissionStatus.SETTLED.getCode());
        settledCommissionWrapper.apply("DATE_FORMAT(settle_time, '%Y-%m') = {0}", yearMonth);
        List<DistributorCommission> settledCommissions = commissionMapper.selectList(settledCommissionWrapper);
        BigDecimal settledCommission = settledCommissions.stream()
                .map(DistributorCommission::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        LambdaQueryWrapper<DistributorCommission> pendingCommissionWrapper = new LambdaQueryWrapper<>();
        pendingCommissionWrapper.eq(DistributorCommission::getDistributorId, distributorId);
        pendingCommissionWrapper.eq(DistributorCommission::getStatus, DistributorCommissionStatus.PENDING.getCode());
        pendingCommissionWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", yearMonth);
        List<DistributorCommission> pendingCommissions = commissionMapper.selectList(pendingCommissionWrapper);
        BigDecimal pendingCommission = pendingCommissions.stream()
                .map(DistributorCommission::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        report.setTotalReferrals(totalReferrals.intValue());
        report.setValidReferrals(validReferrals.intValue());
        report.setPendingReferrals(pendingReferrals.intValue());
        report.setExpiredReferrals(expiredReferrals.intValue());
        report.setTotalCommission(totalCommission);
        report.setSettledCommission(settledCommission);
        report.setPendingCommission(pendingCommission);
        report.setUpdateTime(LocalDateTime.now());

        if (report.getId() == null) {
            reportMapper.insert(report);
        } else {
            reportMapper.updateById(report);
        }

        log.info("[月度报表] 生成完成 - distributorId: {}, yearMonth: {}", distributorId, yearMonth);
        return report;
    }

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

        LambdaQueryWrapper<DistributorMonthlyReport> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(queryDTO.getYearMonth() != null, DistributorMonthlyReport::getYearMonth, queryDTO.getYearMonth());
        wrapper.eq(queryDTO.getDistributorId() != null, DistributorMonthlyReport::getDistributorId, queryDTO.getDistributorId());
        wrapper.orderByDesc(DistributorMonthlyReport::getYearMonth);

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

        return result;
    }

    @Override
    public DistributorDashboardVO getDashboard() {
        try {
            Long totalDistributors = distributorMapper.selectCount(
                    new LambdaQueryWrapper<Distributor>().eq(Distributor::getDeleted, CommonConstants.NOT_DELETED));

            Long activeDistributors = distributorMapper.selectCount(
                    new LambdaQueryWrapper<Distributor>().eq(Distributor::getStatus, DistributorStatus.ACTIVE.getCode()).eq(Distributor::getDeleted, CommonConstants.NOT_DELETED));

            List<Distributor> allDistributors = distributorMapper.selectList(
                    new LambdaQueryWrapper<Distributor>().eq(Distributor::getDeleted, CommonConstants.NOT_DELETED));

            Long totalReferrals = allDistributors.stream()
                    .mapToLong(d -> d.getTotalReferrals() != null ? d.getTotalReferrals() : 0)
                    .sum();

            Long validReferrals = allDistributors.stream()
                    .mapToLong(d -> d.getValidReferrals() != null ? d.getValidReferrals() : 0)
                    .sum();

            BigDecimal totalCommission = allDistributors.stream()
                    .map(d -> d.getTotalCommission() != null ? d.getTotalCommission() : BigDecimal.ZERO)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            String currentMonth = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
            LambdaQueryWrapper<DistributorCommission> monthCommissionWrapper = new LambdaQueryWrapper<>();
            monthCommissionWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", currentMonth);
            List<DistributorCommission> monthCommissions = commissionMapper.selectList(monthCommissionWrapper);
            BigDecimal monthlyCommission = monthCommissions.stream()
                    .map(c -> c.getAmount() != null ? c.getAmount() : BigDecimal.ZERO)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            List<MonthlyTrendVO> trends = buildMonthlyTrends();

            return DistributorDashboardVO.builder()
                    .totalDistributors(totalDistributors)
                    .activeDistributors(activeDistributors)
                    .totalReferrals(totalReferrals)
                    .validReferrals(validReferrals)
                    .totalCommission(totalCommission)
                    .monthlyCommission(monthlyCommission)
                    .trends(trends)
                    .build();
        } catch (Exception e) {
            log.error("获取分销仪表盘数据失败", e);
            return DistributorDashboardVO.builder()
                    .totalDistributors(0L)
                    .activeDistributors(0L)
                    .totalReferrals(0L)
                    .validReferrals(0L)
                    .totalCommission(BigDecimal.ZERO)
                    .monthlyCommission(BigDecimal.ZERO)
                    .trends(new ArrayList<>())
                    .build();
        }
    }

    @Override
    public List<DistributorMonthlyReport> exportMonthlyReport(String yearMonth) {
        List<DistributorMonthlyReport> reports = reportMapper.selectByMonth(yearMonth);
        reports.forEach(this::fillDistributorName);
        return reports;
    }

    private List<MonthlyTrendVO> buildMonthlyTrends() {
        List<MonthlyTrendVO> trends = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

        for (int i = 11; i >= 0; i--) {
            LocalDateTime month = now.minusMonths(i);
            String yearMonth = month.format(formatter);

            LambdaQueryWrapper<DistributorMonthlyReport> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DistributorMonthlyReport::getYearMonth, yearMonth);
            List<DistributorMonthlyReport> monthReports = reportMapper.selectList(wrapper);

            Long referralCount = monthReports.stream()
                    .mapToLong(r -> r.getTotalReferrals() != null ? r.getTotalReferrals() : 0)
                    .sum();

            Long validCount = monthReports.stream()
                    .mapToLong(r -> r.getValidReferrals() != null ? r.getValidReferrals() : 0)
                    .sum();

            BigDecimal commissionAmount = monthReports.stream()
                    .map(r -> r.getTotalCommission() != null ? r.getTotalCommission() : BigDecimal.ZERO)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            trends.add(MonthlyTrendVO.builder()
                    .yearMonth(yearMonth)
                    .referralCount(referralCount)
                    .validCount(validCount)
                    .commissionAmount(commissionAmount)
                    .build());
        }

        return trends;
    }

    private void fillDistributorName(DistributorMonthlyReport report) {
        if (report == null || report.getDistributorId() == null) {
            return;
        }
        Distributor distributor = distributorMapper.selectById(report.getDistributorId());
        if (distributor != null) {
            report.setDistributorName(distributor.getName());
        }
    }
}
