package com.mvrent.carrental.service;

import com.mvrent.carrental.model.*;
import com.mvrent.carrental.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;

/** Aggregates the figures shown on the admin command-center dashboard. */
@Service
@RequiredArgsConstructor
public class DashboardService {

    private static final DateTimeFormatter MONTH = DateTimeFormatter.ofPattern("MMM yy");

    private final BookingRepository bookingRepository;
    private final CarRepository carRepository;
    private final DriverRepository driverRepository;
    private final VendorRepository vendorRepository;
    private final UserRepository userRepository;
    private final CarService carService;
    private final DriverService driverService;

    public DashboardData build() {
        List<Booking> all = bookingRepository.findAllByOrderByCreatedAtDesc();

        BigDecimal totalRevenue = BigDecimal.ZERO;
        BigDecimal ownedRevenue = BigDecimal.ZERO;
        BigDecimal vendorRevenue = BigDecimal.ZERO;
        long pending = 0, confirmed = 0, completed = 0, cancelled = 0;

        Map<YearMonth, BigDecimal> monthlyRev = new TreeMap<>();
        Map<YearMonth, Long> monthlyCnt = new TreeMap<>();

        for (Booking b : all) {
            BigDecimal total = nz(b.getTotalAmount());
            BigDecimal vehicle = b.getVehicleCharge() != null ? b.getVehicleCharge() : total;
            totalRevenue = totalRevenue.add(total);
            if (b.getRevenueOwner() == CarOwnership.VENDOR) vendorRevenue = vendorRevenue.add(vehicle);
            else ownedRevenue = ownedRevenue.add(vehicle);

            switch (b.getStatus()) {
                case PENDING -> pending++;
                case CONFIRMED -> confirmed++;
                case COMPLETED -> completed++;
                case CANCELLED -> cancelled++;
            }

            YearMonth ym = YearMonth.from(b.getPickupDate());
            monthlyRev.merge(ym, total, BigDecimal::add);
            monthlyCnt.merge(ym, 1L, Long::sum);
        }

        // Last 8 active months for the trend chart.
        List<YearMonth> months = new ArrayList<>(monthlyRev.keySet());
        if (months.size() > 8) months = months.subList(months.size() - 8, months.size());
        List<String> monthLabels = new ArrayList<>();
        List<BigDecimal> monthRevenue = new ArrayList<>();
        List<Long> monthCount = new ArrayList<>();
        for (YearMonth ym : months) {
            monthLabels.add(ym.format(MONTH));
            monthRevenue.add(monthlyRev.get(ym));
            monthCount.add(monthlyCnt.get(ym));
        }

        return new DashboardData(
                carRepository.count(),
                driverRepository.count(),
                vendorRepository.count(),
                all.size(),
                userRepository.countByRole(Role.CUSTOMER),
                totalRevenue,
                pending, confirmed, completed, cancelled,
                ownedRevenue, vendorRevenue,
                monthLabels, monthRevenue, monthCount,
                all.stream().limit(6).toList(),
                carService.documentsExpiringWithin(30),
                driverService.documentsExpiringWithin(30)
        );
    }

    private static BigDecimal nz(BigDecimal v) {
        return v == null ? BigDecimal.ZERO : v;
    }

    public record DashboardData(
            long totalCars, long totalDrivers, long totalVendors, long totalBookings, long totalCustomers,
            BigDecimal totalRevenue,
            long pending, long confirmed, long completed, long cancelled,
            BigDecimal ownedRevenue, BigDecimal vendorRevenue,
            List<String> monthLabels, List<BigDecimal> monthRevenue, List<Long> monthCount,
            List<Booking> recentBookings,
            List<CarDocument> expiringCarDocs, List<DriverDocument> expiringDriverDocs
    ) {}
}
