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

namespace PowderCoating.Web.Controllers;

[Authorize(Policy = AppConstants.Policies.SuperAdminOnly)]
public class AnnouncementsController : Controller
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IInAppNotificationService _inApp;

    public AnnouncementsController(IUnitOfWork unitOfWork, IInAppNotificationService inApp)
    {
        _unitOfWork = unitOfWork;
        _inApp = inApp;
    }

    /// <summary>
    /// Lists all platform announcements in reverse-chronological order. SuperAdmin-only (enforced at controller level by the SuperAdminOnly policy).
    /// </summary>
    public async Task<IActionResult> Index()
    {
        var announcements = (await _unitOfWork.Announcements.GetAllAsync())
            .OrderByDescending(a => a.CreatedAt)
            .ToList();
        return View(announcements);
    }

    /// <summary>
    /// Shows the announcement creation form with sensible defaults: starts now, dismissible, and active.
    /// </summary>
    public async Task<IActionResult> Create()
    {
        await PopulateDropdownsAsync();
        return View(new Announcement { StartsAt = DateTime.Now, IsDismissible = true, IsActive = true });
    }

    /// <summary>
    /// Persists a new announcement and immediately dispatches it as in-app notifications to all targeted companies. Dates are converted to UTC before storage; DispatchNotificationsAsync handles the fan-out.
    /// </summary>
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Announcement model)
    {
        if (!ModelState.IsValid) { await PopulateDropdownsAsync(); return View(model); }

        model.CreatedByUserId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "";
        model.CreatedByUserName = User.Identity?.Name ?? "SuperAdmin";
        model.CreatedAt = DateTime.UtcNow;
        model.StartsAt = model.StartsAt.ToUniversalTime();
        if (model.ExpiresAt.HasValue) model.ExpiresAt = model.ExpiresAt.Value.ToUniversalTime();

        await _unitOfWork.Announcements.AddAsync(model);
        await _unitOfWork.CompleteAsync();

        await DispatchNotificationsAsync(model);

        TempData["Success"] = "Announcement created and sent as notifications.";
        return RedirectToAction(nameof(Index));
    }

    /// <summary>
    /// Shows the edit form for an existing announcement. Note: editing does NOT re-dispatch notifications; it only updates the stored announcement record.
    /// </summary>
    public async Task<IActionResult> Edit(int id)
    {
        var announcement = await _unitOfWork.Announcements.GetByIdAsync(id);
        if (announcement == null) return NotFound();
        await PopulateDropdownsAsync();
        return View(announcement);
    }

    /// <summary>
    /// Saves changes to an existing announcement. TargetPlan and TargetCompanyId are cleared when the Target field changes, preventing stale filter values from persisting on the record.
    /// </summary>
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, Announcement model)
    {
        if (!ModelState.IsValid) { await PopulateDropdownsAsync(); return View(model); }

        var existing = await _unitOfWork.Announcements.GetByIdAsync(id);
        if (existing == null) return NotFound();

        existing.Title = model.Title;
        existing.Message = model.Message;
        existing.Type = model.Type;
        existing.Target = model.Target;
        existing.TargetPlan = model.Target == "Plan" ? model.TargetPlan : null;
        existing.TargetCompanyId = model.Target == "Company" ? model.TargetCompanyId : null;
        existing.StartsAt = model.StartsAt.ToUniversalTime();
        existing.ExpiresAt = model.ExpiresAt.HasValue ? model.ExpiresAt.Value.ToUniversalTime() : null;
        existing.IsDismissible = model.IsDismissible;
        existing.IsActive = model.IsActive;
        existing.UpdatedAt = DateTime.UtcNow;

        await _unitOfWork.CompleteAsync();
        TempData["Success"] = "Announcement updated.";
        return RedirectToAction(nameof(Index));
    }

    /// <summary>
    /// Permanently deletes an announcement record. Hard delete is intentional here — announcements are platform content, not business data, and do not require audit-trail soft deletion.
    /// </summary>
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<IActionResult> Delete(int id)
    {
        var announcement = await _unitOfWork.Announcements.GetByIdAsync(id);
        if (announcement == null) return NotFound();
        await _unitOfWork.Announcements.DeleteAsync(announcement);
        await _unitOfWork.CompleteAsync();
        TempData["Success"] = "Announcement deleted.";
        return RedirectToAction(nameof(Index));
    }

    /// <summary>
    /// Fans out the announcement as in-app notifications to each matching company. IgnoreQueryFilters is required to reach all active companies regardless of tenant context. Filtering by Target/Plan/Company happens after the fetch so only relevant tenants receive the notification.
    /// </summary>
    private async Task DispatchNotificationsAsync(Announcement model)
    {
        var companies = (await _unitOfWork.Companies.FindAsync(
            c => !c.IsDeleted && c.IsActive, ignoreQueryFilters: true)).ToList();

        if (model.Target == "Plan" && model.TargetPlan.HasValue)
            companies = companies.Where(c => c.SubscriptionPlan == model.TargetPlan.Value).ToList();
        else if (model.Target == "Company" && model.TargetCompanyId.HasValue)
            companies = companies.Where(c => c.Id == model.TargetCompanyId.Value).ToList();

        foreach (var company in companies)
            await _inApp.CreateAsync(company.Id, model.Title, model.Message, "Announcement");
    }

    /// <summary>
    /// Loads company and plan lists into ViewBag for the Create/Edit form dropdowns. Uses IgnoreQueryFilters to bypass soft-delete and tenant filters so all companies are available for targeting.
    /// </summary>
    private async Task PopulateDropdownsAsync()
    {
        ViewBag.Companies = (await _unitOfWork.Companies.FindAsync(c => !c.IsDeleted, ignoreQueryFilters: true))
            .OrderBy(c => c.CompanyName)
            .Select(c => new { c.Id, c.CompanyName })
            .ToList();
        ViewBag.PlanConfigs = (await _unitOfWork.SubscriptionPlanConfigs.FindAsync(p => p.IsActive, ignoreQueryFilters: true))
            .OrderBy(p => p.SortOrder)
            .ToList();
    }
}
