using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PowderCoating.Core.Enums;
using PowderCoating.Core.Interfaces;
using PowderCoating.Shared.Constants;

namespace PowderCoating.Web.Controllers;

/// <summary>
/// SuperAdmin-only cross-company notification log viewer.
/// The company-scoped version lives in NotificationLogsController (CanManageJobs policy).
/// Uses IgnoreQueryFilters throughout to bypass the multi-tenancy global filter and see
/// logs from all companies simultaneously.
/// </summary>
[Authorize(Policy = AppConstants.Policies.SuperAdminOnly)]
public class PlatformNotificationsController : Controller
{
    private readonly IUnitOfWork _unitOfWork;

    public PlatformNotificationsController(IUnitOfWork unitOfWork) => _unitOfWork = unitOfWork;

    /// <summary>
    /// Renders a paginated, filterable cross-company notification log view visible only to SuperAdmins.
    /// All filter/sort/paging is applied in-memory after a single filtered repository fetch.
    /// Company names are resolved in a follow-up batch query keyed on the page's distinct company IDs.
    /// Summary counts reflect the full unfiltered dataset so the health cards are accurate regardless of active filters.
    /// </summary>
    public async Task<IActionResult> Index(
        int? companyId,
        string? type,
        string? status,
        string? channel,
        string? search,
        DateTime? from,
        DateTime? to,
        int page = 1,
        int pageSize = 50)
    {
        pageSize = pageSize is 25 or 50 or 100 ? pageSize : 50;
        page = Math.Max(1, page);

        // Load all non-deleted logs across all tenants, then filter in-memory.
        var all = (await _unitOfWork.NotificationLogs.FindAsync(n => !n.IsDeleted, ignoreQueryFilters: true))
            .AsEnumerable();

        if (companyId.HasValue)
            all = all.Where(n => n.CompanyId == companyId);

        if (!string.IsNullOrWhiteSpace(type) && Enum.TryParse<NotificationType>(type, out var typeEnum))
            all = all.Where(n => n.NotificationType == typeEnum);

        if (!string.IsNullOrWhiteSpace(status) && Enum.TryParse<NotificationStatus>(status, out var statusEnum))
            all = all.Where(n => n.Status == statusEnum);

        if (!string.IsNullOrWhiteSpace(channel) && Enum.TryParse<NotificationChannel>(channel, out var channelEnum))
            all = all.Where(n => n.Channel == channelEnum);

        if (!string.IsNullOrWhiteSpace(search))
            all = all.Where(n =>
                n.RecipientName.Contains(search, StringComparison.OrdinalIgnoreCase) ||
                n.Recipient.Contains(search, StringComparison.OrdinalIgnoreCase) ||
                (n.Subject != null && n.Subject.Contains(search, StringComparison.OrdinalIgnoreCase)));

        if (from.HasValue)
            all = all.Where(n => n.SentAt >= from.Value.Date);

        if (to.HasValue)
            all = all.Where(n => n.SentAt < to.Value.Date.AddDays(1));

        var filtered = all.OrderByDescending(n => n.SentAt).ToList();
        var totalCount = filtered.Count;

        var items = filtered
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(n => new PlatformNotificationRow
            {
                Id = n.Id,
                CompanyId = (int)n.CompanyId,
                Channel = n.Channel,
                NotificationType = n.NotificationType,
                Status = n.Status,
                RecipientName = n.RecipientName,
                Recipient = n.Recipient,
                Subject = n.Subject,
                ErrorMessage = n.ErrorMessage,
                SentAt = n.SentAt
            })
            .ToList();

        // Resolve company names for the page's rows in one query
        var cids = items.Select(i => i.CompanyId).Distinct().ToList();
        var companyNames = (await _unitOfWork.Companies.FindAsync(c => cids.Contains(c.Id), ignoreQueryFilters: true))
            .ToDictionary(c => c.Id, c => c.CompanyName);
        foreach (var item in items)
            item.CompanyName = companyNames.GetValueOrDefault(item.CompanyId);

        // Sidebar company list for filter dropdown
        var companies = (await _unitOfWork.Companies.FindAsync(c => !c.IsDeleted, ignoreQueryFilters: true))
            .OrderBy(c => c.CompanyName)
            .Select(c => new { c.Id, c.CompanyName })
            .ToList();

        // Summary counts from the unfiltered dataset
        var allLogs = await _unitOfWork.NotificationLogs.FindAsync(n => !n.IsDeleted, ignoreQueryFilters: true);
        ViewBag.TotalCount = allLogs.Count();
        ViewBag.FailedCount = allLogs.Count(n => n.Status == NotificationStatus.Failed);
        ViewBag.Last24hCount = allLogs.Count(n => n.SentAt >= DateTime.UtcNow.AddHours(-24));

        ViewBag.Companies = companies;
        ViewBag.CompanyIdFilter = companyId;
        ViewBag.TypeFilter = type;
        ViewBag.StatusFilter = status;
        ViewBag.ChannelFilter = channel;
        ViewBag.Search = search;
        ViewBag.From = from?.ToString("yyyy-MM-dd");
        ViewBag.To = to?.ToString("yyyy-MM-dd");
        ViewBag.Page = page;
        ViewBag.PageSize = pageSize;
        ViewBag.FilteredCount = totalCount;
        ViewBag.TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize);

        return View(items);
    }

    /// <summary>
    /// Returns the full notification log entry for the given id, including the complete message body and error details.
    /// </summary>
    public async Task<IActionResult> Details(int id)
    {
        var log = await _unitOfWork.NotificationLogs.FirstOrDefaultAsync(n => n.Id == id, ignoreQueryFilters: true);
        if (log == null) return NotFound();

        string? companyName = null;
        if (log.CompanyId > 0)
            companyName = (await _unitOfWork.Companies.FirstOrDefaultAsync(
                c => c.Id == log.CompanyId, ignoreQueryFilters: true))?.CompanyName;

        ViewBag.CompanyName = companyName;
        return View(log);
    }
}

public class PlatformNotificationRow
{
    public int Id { get; set; }
    public int CompanyId { get; set; }
    public string? CompanyName { get; set; }
    public NotificationChannel Channel { get; set; }
    public NotificationType NotificationType { get; set; }
    public NotificationStatus Status { get; set; }
    public string RecipientName { get; set; } = string.Empty;
    public string Recipient { get; set; } = string.Empty;
    public string? Subject { get; set; }
    public string? ErrorMessage { get; set; }
    public DateTime SentAt { get; set; }
}
