using MediatR;
using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.Reports.Dtos;
using SolutionErp.Domain.Contracts;

namespace SolutionErp.Application.Reports.Queries.GetDashboardStats;

public record GetDashboardStatsQuery : IRequest<DashboardStatsDto>;

public class GetDashboardStatsQueryHandler(IApplicationDbContext db, IDateTime dateTime)
    : IRequestHandler<GetDashboardStatsQuery, DashboardStatsDto>
{
    public async Task<DashboardStatsDto> Handle(GetDashboardStatsQuery request, CancellationToken ct)
    {
        var now = dateTime.UtcNow;
        var monthStart = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc);
        var earliest = now.AddMonths(-11);
        var earliestMonth = new DateTime(earliest.Year, earliest.Month, 1, 0, 0, 0, DateTimeKind.Utc);

        var total = await db.Contracts.AsNoTracking().CountAsync(ct);
        var active = await db.Contracts.AsNoTracking()
            .CountAsync(c => c.Phase != ContractPhase.DaPhatHanh && c.Phase != ContractPhase.TuChoi, ct);
        var overdue = await db.Contracts.AsNoTracking()
            .CountAsync(c => c.SlaDeadline != null && c.SlaDeadline < now
                && c.Phase != ContractPhase.DaPhatHanh && c.Phase != ContractPhase.TuChoi, ct);
        var publishedThisMonth = await db.Contracts.AsNoTracking()
            .CountAsync(c => c.Phase == ContractPhase.DaPhatHanh && c.UpdatedAt != null && c.UpdatedAt >= monthStart, ct);
        var totalValueActive = await db.Contracts.AsNoTracking()
            .Where(c => c.Phase != ContractPhase.DaPhatHanh && c.Phase != ContractPhase.TuChoi)
            .SumAsync(c => (decimal?)c.GiaTri, ct) ?? 0m;

        var byPhase = await db.Contracts.AsNoTracking()
            .GroupBy(c => c.Phase)
            .Select(g => new PhaseCountDto(g.Key, g.Count()))
            .ToListAsync(ct);

        var topSuppliers = await (from c in db.Contracts.AsNoTracking()
                                  join s in db.Suppliers.AsNoTracking() on c.SupplierId equals s.Id
                                  group new { c, s } by new { c.SupplierId, s.Name } into g
                                  orderby g.Count() descending
                                  select new SupplierCountDto(g.Key.SupplierId, g.Key.Name, g.Count(), g.Sum(x => x.c.GiaTri)))
            .Take(5)
            .ToListAsync(ct);

        var topProjects = await (from c in db.Contracts.AsNoTracking()
                                 join p in db.Projects.AsNoTracking() on c.ProjectId equals p.Id
                                 group new { c, p } by new { c.ProjectId, p.Name } into g
                                 orderby g.Count() descending
                                 select new ProjectCountDto(g.Key.ProjectId, g.Key.Name, g.Count(), g.Sum(x => x.c.GiaTri)))
            .Take(5)
            .ToListAsync(ct);

        var monthlyRaw = await db.Contracts.AsNoTracking()
            .Where(c => c.CreatedAt >= earliestMonth)
            .GroupBy(c => new { c.CreatedAt.Year, c.CreatedAt.Month })
            .Select(g => new { g.Key.Year, g.Key.Month, TotalValue = g.Sum(c => c.GiaTri), Count = g.Count() })
            .ToListAsync(ct);

        // Fill 12 tháng liên tục (kể cả tháng không có data)
        var monthly = new List<MonthlyValueDto>();
        for (int i = 0; i < 12; i++)
        {
            var d = earliestMonth.AddMonths(i);
            var row = monthlyRaw.FirstOrDefault(r => r.Year == d.Year && r.Month == d.Month);
            monthly.Add(new MonthlyValueDto(d.Year, d.Month, row?.TotalValue ?? 0m, row?.Count ?? 0));
        }

        return new DashboardStatsDto(
            total, active, overdue, publishedThisMonth, totalValueActive,
            byPhase, topSuppliers, topProjects, monthly);
    }
}
