using AdsBillingService.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace AdsBillingService.API.Controllers.Admin;

/// <summary>
/// EN: Admin controller for managing ad charges.
/// VI: Admin controller quản lý charge quảng cáo.
/// </summary>
[ApiController]
[Route("api/v1/admin/ads-billing/charges")]
[Produces("application/json")]
public class AdminChargesController : ControllerBase
{
    private readonly AdsBillingServiceContext _context;
    private readonly ILogger<AdminChargesController> _logger;

    public AdminChargesController(
        AdsBillingServiceContext context,
        ILogger<AdminChargesController> logger)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// EN: Get charges with filters.
    /// VI: Lấy danh sách charges với bộ lọc.
    /// </summary>
    [HttpGet]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetCharges(
        [FromQuery] Guid? advertiserId = null,
        [FromQuery] Guid? campaignId = null,
        [FromQuery] string? chargeType = null,
        [FromQuery] bool? processed = null,
        [FromQuery] DateTime? fromDate = null,
        [FromQuery] DateTime? toDate = null,
        [FromQuery] int pageNumber = 1,
        [FromQuery] int pageSize = 50)
    {
        _logger.LogInformation("Getting charges with filters");

        var query = _context.AdCharges.AsNoTracking();

        if (advertiserId.HasValue)
        {
            query = query.Where(c => c.AdvertiserId == advertiserId.Value);
        }

        if (campaignId.HasValue)
        {
            query = query.Where(c => c.CampaignId == campaignId.Value);
        }

        if (!string.IsNullOrEmpty(chargeType))
        {
            query = query.Where(c => c.ChargeType.ToString() == chargeType);
        }

        if (processed.HasValue)
        {
            query = query.Where(c => c.Processed == processed.Value);
        }

        if (fromDate.HasValue)
        {
            query = query.Where(c => c.ChargedAt >= fromDate.Value);
        }

        if (toDate.HasValue)
        {
            query = query.Where(c => c.ChargedAt <= toDate.Value);
        }

        var charges = await query
            .OrderByDescending(c => c.ChargedAt)
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .Select(c => new
            {
                c.Id,
                c.AdvertiserId,
                c.CampaignId,
                c.AdId,
                ChargeType = c.ChargeType.ToString(),
                c.Amount,
                c.Currency,
                c.ChargedAt,
                c.Processed
            })
            .ToListAsync();

        return Ok(new { pageNumber, pageSize, total = charges.Count, data = charges });
    }

    /// <summary>
    /// EN: Get charge statistics and analytics.
    /// VI: Lấy thống kê và phân tích charge.
    /// </summary>
    [HttpGet("stats")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetStatistics()
    {
        _logger.LogInformation("Getting charge statistics");

        var totalCharges = await _context.AdCharges.CountAsync();
        var processedCharges = await _context.AdCharges.CountAsync(c => c.Processed);
        var unprocessedCharges = totalCharges - processedCharges;

        var totalAmount = await _context.AdCharges.SumAsync(c => c.Amount);
        var processedAmount = await _context.AdCharges
            .Where(c => c.Processed)
            .SumAsync(c => c.Amount);

        var chargesByType = await _context.AdCharges
            .GroupBy(c => c.ChargeType)
            .Select(g => new
            {
                ChargeType = g.Key.ToString(),
                Count = g.Count(),
                TotalAmount = g.Sum(c => c.Amount)
            })
            .ToListAsync();

        var recentCharges = await _context.AdCharges
            .OrderByDescending(c => c.ChargedAt)
            .Take(10)
            .Select(c => new
            {
                c.Id,
                c.AdvertiserId,
                c.CampaignId,
                ChargeType = c.ChargeType.ToString(),
                c.Amount,
                c.ChargedAt
            })
            .ToListAsync();

        return Ok(new
        {
            summary = new
            {
                totalCharges,
                processedCharges,
                unprocessedCharges,
                totalAmount,
                processedAmount,
                unprocessedAmount = totalAmount - processedAmount
            },
            byType = chargesByType,
            recentCharges
        });
    }

    /// <summary>
    /// EN: Get charge analytics by advertiser.
    /// VI: Lấy phân tích charge theo advertiser.
    /// </summary>
    [HttpGet("analytics/by-advertiser")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetAdvertiserAnalytics([FromQuery] int top = 10)
    {
        _logger.LogInformation("Getting top {Top} advertisers by charges", top);

        var analytics = await _context.AdCharges
            .GroupBy(c => c.AdvertiserId)
            .Select(g => new
            {
                AdvertiserId = g.Key,
                TotalCharges = g.Count(),
                TotalAmount = g.Sum(c => c.Amount),
                ProcessedCharges = g.Count(c => c.Processed),
                UnprocessedCharges = g.Count(c => !c.Processed)
            })
            .OrderByDescending(a => a.TotalAmount)
            .Take(top)
            .ToListAsync();

        return Ok(analytics);
    }
}
