package com.erp.purchase.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.erp.purchase.dto.PurchaseStatisticsDTO;
import com.erp.purchase.entity.PurchaseInbound;
import com.erp.purchase.entity.PurchaseOrder;
import com.erp.purchase.entity.PurchaseReturn;
import com.erp.purchase.mapper.PurchaseInboundMapper;
import com.erp.purchase.mapper.PurchaseOrderMapper;
import com.erp.purchase.mapper.PurchaseReturnMapper;
import com.erp.purchase.service.PurchaseStatisticsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PurchaseStatisticsServiceImpl implements PurchaseStatisticsService {

    private final PurchaseOrderMapper purchaseOrderMapper;
    private final PurchaseInboundMapper purchaseInboundMapper;
    private final PurchaseReturnMapper purchaseReturnMapper;

    @Override
    public PurchaseStatisticsDTO.SummaryVO getSummary(PurchaseStatisticsDTO.QueryRequest query) {
        LambdaQueryWrapper<PurchaseOrder> orderWrapper = new LambdaQueryWrapper<>();
        if (query.getStartDate() != null) orderWrapper.ge(PurchaseOrder::getOrderDate, query.getStartDate());
        if (query.getEndDate() != null) orderWrapper.le(PurchaseOrder::getOrderDate, query.getEndDate());
        if (query.getSupplierId() != null) orderWrapper.eq(PurchaseOrder::getSupplierId, query.getSupplierId());
        orderWrapper.eq(PurchaseOrder::getDeleted, 0);

        List<PurchaseOrder> orders = purchaseOrderMapper.selectList(orderWrapper);

        long orderCount = orders.size();
        BigDecimal totalAmount = orders.stream()
                .map(PurchaseOrder::getTotalAmount)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalTax = orders.stream()
                .map(PurchaseOrder::getTaxAmount)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalWithTax = orders.stream()
                .map(PurchaseOrder::getTotalWithTax)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal inboundAmount = orders.stream()
                .map(PurchaseOrder::getInboundAmount)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal paidAmount = orders.stream()
                .map(PurchaseOrder::getPaidAmount)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal inboundRate = BigDecimal.ZERO;
        if (totalWithTax.compareTo(BigDecimal.ZERO) > 0) {
            inboundRate = inboundAmount.divide(totalWithTax, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
        }

        BigDecimal paymentRate = BigDecimal.ZERO;
        if (totalWithTax.compareTo(BigDecimal.ZERO) > 0) {
            paymentRate = paidAmount.divide(totalWithTax, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
        }

        LambdaQueryWrapper<PurchaseReturn> returnWrapper = new LambdaQueryWrapper<>();
        if (query.getStartDate() != null) returnWrapper.ge(PurchaseReturn::getCreateTime, query.getStartDate().atStartOfDay());
        if (query.getEndDate() != null) returnWrapper.le(PurchaseReturn::getCreateTime, query.getEndDate().atTime(23, 59, 59));
        if (query.getSupplierId() != null) returnWrapper.eq(PurchaseReturn::getSupplierId, query.getSupplierId());
        returnWrapper.eq(PurchaseReturn::getDeleted, 0);

        List<PurchaseReturn> returns = purchaseReturnMapper.selectList(returnWrapper);
        long returnCount = returns.size();
        BigDecimal returnAmount = returns.stream()
                .map(PurchaseReturn::getTotalAmount)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal returnRate = BigDecimal.ZERO;
        if (totalWithTax.compareTo(BigDecimal.ZERO) > 0) {
            returnRate = returnAmount.divide(totalWithTax, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
        }

        return PurchaseStatisticsDTO.SummaryVO.builder()
                .orderCount(orderCount)
                .totalAmount(totalAmount)
                .totalTax(totalTax)
                .totalWithTax(totalWithTax)
                .inboundAmount(inboundAmount)
                .inboundRate(inboundRate)
                .paidAmount(paidAmount)
                .paymentRate(paymentRate)
                .returnCount(returnCount)
                .returnAmount(returnAmount)
                .returnRate(returnRate)
                .build();
    }

    @Override
    public List<PurchaseStatisticsDTO.SupplierStatVO> getSupplierStats(PurchaseStatisticsDTO.QueryRequest query) {
        LambdaQueryWrapper<PurchaseOrder> wrapper = new LambdaQueryWrapper<>();
        if (query.getStartDate() != null) wrapper.ge(PurchaseOrder::getOrderDate, query.getStartDate());
        if (query.getEndDate() != null) wrapper.le(PurchaseOrder::getOrderDate, query.getEndDate());
        if (query.getSupplierId() != null) wrapper.eq(PurchaseOrder::getSupplierId, query.getSupplierId());
        wrapper.eq(PurchaseOrder::getDeleted, 0);

        List<PurchaseOrder> orders = purchaseOrderMapper.selectList(wrapper);

        Map<Long, List<PurchaseOrder>> bySupplier = orders.stream()
                .collect(Collectors.groupingBy(PurchaseOrder::getSupplierId));

        List<PurchaseStatisticsDTO.SupplierStatVO> stats = new ArrayList<>();
        for (Map.Entry<Long, List<PurchaseOrder>> entry : bySupplier.entrySet()) {
            List<PurchaseOrder> supplierOrders = entry.getValue();
            String supplierName = supplierOrders.get(0).getSupplierName();
            BigDecimal totalAmt = supplierOrders.stream()
                    .map(PurchaseOrder::getTotalWithTax)
                    .filter(v -> v != null)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal inboundAmt = supplierOrders.stream()
                    .map(PurchaseOrder::getInboundAmount)
                    .filter(v -> v != null)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal paidAmt = supplierOrders.stream()
                    .map(PurchaseOrder::getPaidAmount)
                    .filter(v -> v != null)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal inboundRate = totalAmt.compareTo(BigDecimal.ZERO) > 0
                    ? inboundAmt.divide(totalAmt, 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP)
                    : BigDecimal.ZERO;

            stats.add(PurchaseStatisticsDTO.SupplierStatVO.builder()
                    .supplierId(entry.getKey())
                    .supplierName(supplierName)
                    .orderCount((long) supplierOrders.size())
                    .totalAmount(totalAmt)
                    .inboundAmount(inboundAmt)
                    .inboundRate(inboundRate)
                    .paidAmount(paidAmt)
                    .build());
        }

        stats.sort((a, b) -> b.getTotalAmount().compareTo(a.getTotalAmount()));
        return stats;
    }

    @Override
    public List<PurchaseStatisticsDTO.DailyStatVO> getDailyStats(PurchaseStatisticsDTO.QueryRequest query) {
        LambdaQueryWrapper<PurchaseOrder> wrapper = new LambdaQueryWrapper<>();
        if (query.getStartDate() != null) wrapper.ge(PurchaseOrder::getOrderDate, query.getStartDate());
        if (query.getEndDate() != null) wrapper.le(PurchaseOrder::getOrderDate, query.getEndDate());
        if (query.getSupplierId() != null) wrapper.eq(PurchaseOrder::getSupplierId, query.getSupplierId());
        wrapper.eq(PurchaseOrder::getDeleted, 0);
        wrapper.orderByAsc(PurchaseOrder::getOrderDate);

        List<PurchaseOrder> orders = purchaseOrderMapper.selectList(wrapper);

        Map<LocalDate, List<PurchaseOrder>> byDate = orders.stream()
                .collect(Collectors.groupingBy(PurchaseOrder::getOrderDate));

        List<PurchaseStatisticsDTO.DailyStatVO> dailyStats = new ArrayList<>();
        for (Map.Entry<LocalDate, List<PurchaseOrder>> entry : byDate.entrySet()) {
            BigDecimal dailyAmt = entry.getValue().stream()
                    .map(PurchaseOrder::getTotalWithTax)
                    .filter(v -> v != null)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            dailyStats.add(PurchaseStatisticsDTO.DailyStatVO.builder()
                    .date(entry.getKey())
                    .orderCount((long) entry.getValue().size())
                    .amount(dailyAmt)
                    .inboundQuantity(null) // 可按需关联入库明细计算
                    .build());
        }

        return dailyStats;
    }
}
