using MemberCenter.Application.Abstractions;
using MemberCenter.Application.Constants;
using MemberCenter.Domain.Constants;
using MemberCenter.Infrastructure.Persistence;
using MemberCenter.Web.Authorization;
using MemberCenter.Web.Areas.Admin.Models;
using MemberCenter.Web.Models.Admin;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace MemberCenter.Web.Areas.Admin.Controllers;

[Area("Admin")]
[Authorize(Policy = "Admin")]
[AdminPermission(AdminPermissions.NewsletterLists)]
[Route("admin/newsletter-lists")]
public class NewsletterListsController : Controller
{
    private readonly INewsletterListService _listService;
    private readonly ITenantService _tenantService;
    private readonly MemberCenterDbContext _dbContext;

    public NewsletterListsController(
        INewsletterListService listService,
        ITenantService tenantService,
        MemberCenterDbContext dbContext)
    {
        _listService = listService;
        _tenantService = tenantService;
        _dbContext = dbContext;
    }

    [HttpGet("")]
    [AdminPermission(AdminPermissions.NewsletterListsIndex)]
    public async Task<IActionResult> Index()
    {
        var lists = await _listService.ListAsync();
        var counts = await _dbContext.NewsletterSubscriptions
            .Where(subscription => subscription.Status == SubscriptionStatus.Active)
            .GroupBy(subscription => subscription.ListId)
            .Select(group => new { ListId = group.Key, Count = group.Count() })
            .ToDictionaryAsync(group => group.ListId, group => group.Count);

        return View(lists.Select(list => new NewsletterListIndexRowViewModel
        {
            NewsletterList = list,
            ActiveSubscriptionCount = counts.TryGetValue(list.Id, out var count) ? count : 0
        }).ToList());
    }

    [HttpGet("{id:guid}")]
    [AdminPermission(AdminPermissions.NewsletterListsIndex)]
    public async Task<IActionResult> Details(Guid id, string tab = "subscribers")
    {
        var list = await _listService.GetAsync(id);
        if (list is null)
        {
            return NotFound();
        }

        tab = NormalizeTab(tab);
        var activeCount = await _dbContext.NewsletterSubscriptions
            .CountAsync(subscription => subscription.ListId == id && subscription.Status == SubscriptionStatus.Active);
        var unsubscribedCount = await _dbContext.NewsletterSubscriptions
            .CountAsync(subscription => subscription.ListId == id && subscription.Status == SubscriptionStatus.Unsubscribed);

        var rows = tab switch
        {
            "unsubscribed" => await BuildSubscriptionRowsAsync(id, SubscriptionStatus.Unsubscribed),
            "blacklisted" => await BuildBlacklistedRowsAsync(id),
            _ => await BuildSubscriptionRowsAsync(id, SubscriptionStatus.Active)
        };

        return View(new NewsletterListDetailViewModel
        {
            NewsletterList = list,
            Tab = tab,
            ActiveSubscriptionCount = activeCount,
            UnsubscribedCount = unsubscribedCount,
            Rows = rows
        });
    }

    [HttpGet("create")]
    [AdminPermission(AdminPermissions.NewsletterListsCreate)]
    public async Task<IActionResult> Create()
    {
        var tenants = await _tenantService.ListAsync();
        return View(new NewsletterListFormViewModel
        {
            Tenants = tenants
        });
    }

    [HttpPost("create")]
    [AdminPermission(AdminPermissions.NewsletterListsCreate)]
    public async Task<IActionResult> Create(NewsletterListFormViewModel model)
    {
        if (!ModelState.IsValid)
        {
            model.Tenants = await _tenantService.ListAsync();
            return View(model);
        }

        await _listService.CreateAsync(model.TenantId, model.Name, model.Status);
        return RedirectToAction("Index");
    }

    [HttpGet("edit/{id:guid}")]
    [AdminPermission(AdminPermissions.NewsletterListsEdit)]
    public async Task<IActionResult> Edit(Guid id)
    {
        var list = await _listService.GetAsync(id);
        if (list is null)
        {
            return NotFound();
        }

        var tenants = await _tenantService.ListAsync();
        return View(new NewsletterListFormViewModel
        {
            Id = list.Id,
            TenantId = list.TenantId,
            Name = list.Name,
            Status = list.Status,
            Tenants = tenants
        });
    }

    [HttpPost("edit/{id:guid}")]
    [AdminPermission(AdminPermissions.NewsletterListsEdit)]
    public async Task<IActionResult> Edit(Guid id, NewsletterListFormViewModel model)
    {
        if (!ModelState.IsValid)
        {
            model.Tenants = await _tenantService.ListAsync();
            return View(model);
        }

        var updated = await _listService.UpdateAsync(id, model.TenantId, model.Name, model.Status);
        if (updated is null)
        {
            return NotFound();
        }

        return RedirectToAction("Index");
    }

    [HttpPost("delete/{id:guid}")]
    [AdminPermission(AdminPermissions.NewsletterListsDelete)]
    public async Task<IActionResult> Delete(Guid id)
    {
        await _listService.DeleteAsync(id);
        return RedirectToAction("Index");
    }

    private async Task<IReadOnlyList<NewsletterSubscriberRowViewModel>> BuildSubscriptionRowsAsync(Guid listId, string status)
    {
        return await _dbContext.NewsletterSubscriptions
            .Where(subscription => subscription.ListId == listId && subscription.Status == status)
            .OrderByDescending(subscription => subscription.CreatedAt)
            .Select(subscription => new NewsletterSubscriberRowViewModel
            {
                Id = subscription.Id,
                Email = subscription.Email,
                ListId = subscription.ListId.ToString(),
                Status = subscription.Status,
                CreatedAt = subscription.CreatedAt
            })
            .ToListAsync();
    }

    private async Task<IReadOnlyList<NewsletterSubscriberRowViewModel>> BuildBlacklistedRowsAsync(Guid listId)
    {
        var blacklistedEmails = _dbContext.EmailBlacklist.Select(item => item.Email);

        return await _dbContext.NewsletterSubscriptions
            .Where(subscription => subscription.ListId == listId && blacklistedEmails.Contains(subscription.Email.ToLower()))
            .OrderByDescending(subscription => subscription.CreatedAt)
            .Select(subscription => new NewsletterSubscriberRowViewModel
            {
                Id = subscription.Id,
                Email = subscription.Email,
                ListId = subscription.ListId.ToString(),
                Status = subscription.Status,
                CreatedAt = subscription.CreatedAt,
                Reason = _dbContext.EmailBlacklist
                    .Where(item => item.Email == subscription.Email.ToLower())
                    .Select(item => item.Reason)
                    .FirstOrDefault()
            })
            .ToListAsync();
    }

    private static string NormalizeTab(string? tab) =>
        tab?.ToLowerInvariant() switch
        {
            "unsubscribed" => "unsubscribed",
            "blacklisted" => "blacklisted",
            _ => "subscribers"
        };
}
