using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using PlotLine.Services;
using PlotLine.ViewModels;
using System.Net;

namespace PlotLine.Controllers;

[Route("help")]
[AllowAnonymous]
public sealed class HelpController(IHelpService help, IHelpMarkdownRenderer markdown, IConfiguration configuration) : Controller
{
    [HttpGet("", Name = PublicRouteNames.Help)]
    public IActionResult Index(string? q)
    {
        if (!IsCanonicalPath("/help"))
        {
            return RedirectPermanent(PreserveQuery("/help"));
        }

        var canonicalUrl = PublicSeo.AbsoluteUrl(configuration, "/help");
        const string description = "Browse PlotDirector help articles covering projects, books, chapters, scenes, timelines, continuity, characters, locations, and writing tools.";
        PublicSeo.Apply(ViewData, configuration, new SeoMetadata
        {
            Title = "Help Centre",
            Description = description,
            Keywords = "PlotDirector help, writing software help, story planning help, novel planning guides",
            CanonicalPath = "/help",
            JsonLd =
            [
                PublicSeo.JsonLd(new Dictionary<string, object?>
                {
                    ["@context"] = "https://schema.org",
                    ["@type"] = "CollectionPage",
                    ["name"] = "Help Centre",
                    ["url"] = canonicalUrl,
                    ["description"] = description
                }),
                PublicSeo.BreadcrumbJsonLd(
                    ("Help", canonicalUrl))
            ]
        });
        var articles = help.GetAllArticles();
        return View(new HelpCentreIndexViewModel
        {
            Query = q,
            ArticleCount = articles.Count,
            Categories = help.GetCategories()
                .Select(category => new HelpCategoryViewModel
                {
                    CategoryName = category,
                    CategorySlug = HelpService.Slugify(category),
                    ArticleCount = help.GetByCategory(category).Count
                })
                .ToList(),
            SearchResults = string.IsNullOrWhiteSpace(q) ? [] : help.Search(q),
            RecentArticles = articles.OrderByDescending(x => x.RelativePath).Take(5).ToList()
        });
    }

    [HttpGet("{categorySlug}", Name = PublicRouteNames.HelpCategory)]
    public IActionResult Category(string categorySlug)
    {
        var category = help.GetCategoryBySlug(categorySlug);
        if (category is null)
        {
            return NotFound();
        }

        var canonicalPath = $"/help/{HelpService.Slugify(category)}";
        if (!IsCanonicalPath(canonicalPath))
        {
            return RedirectPermanent(canonicalPath);
        }

        var articles = help.GetByCategorySlug(categorySlug);
        var canonicalUrl = PublicSeo.AbsoluteUrl(configuration, canonicalPath);
        var description = CategoryDescription(category);
        PublicSeo.Apply(ViewData, configuration, new SeoMetadata
        {
            Title = $"{category} Help",
            Description = description,
            Keywords = PublicSeo.Keywords([category, "PlotDirector help", "novel planning guides"], articles.SelectMany(article => article.Tags)),
            CanonicalPath = canonicalPath,
            JsonLd =
            [
                PublicSeo.JsonLd(new Dictionary<string, object?>
                {
                    ["@context"] = "https://schema.org",
                    ["@type"] = "CollectionPage",
                    ["name"] = $"{category} Help",
                    ["url"] = canonicalUrl,
                    ["description"] = description
                }),
                PublicSeo.BreadcrumbJsonLd(
                    ("Help", PublicSeo.AbsoluteUrl(configuration, "/help")),
                    (category, canonicalUrl))
            ]
        });
        return View(new HelpCategoryArticlesViewModel
        {
            CategoryName = category,
            CategorySlug = HelpService.Slugify(category),
            Articles = articles
        });
    }

    [HttpGet("{categorySlug}/{articleSlug}", Name = PublicRouteNames.HelpArticle)]
    public IActionResult Article(string categorySlug, string articleSlug)
    {
        var article = help.GetBySlugs(categorySlug, articleSlug);
        if (article is null)
        {
            return View("ArticleNotFound", $"{categorySlug}/{articleSlug}");
        }

        if (!IsCanonicalPath(article.Url))
        {
            return RedirectPermanent(article.Url);
        }

        var canonicalUrl = PublicSeo.AbsoluteUrl(configuration, article.Url);
        var description = PublicSeo.HelpArticleDescription(article, help.GetAllArticles());
        PublicSeo.Apply(ViewData, configuration, new SeoMetadata
        {
            Title = article.Title,
            Description = description,
            Keywords = PublicSeo.Keywords([article.Category, article.Title, "PlotDirector help"], article.Tags),
            CanonicalPath = article.Url,
            OgType = "article",
            JsonLd =
            [
                PublicSeo.JsonLd(new Dictionary<string, object?>
                {
                    ["@context"] = "https://schema.org",
                    ["@type"] = "TechArticle",
                    ["headline"] = article.Title,
                    ["name"] = article.Title,
                    ["url"] = canonicalUrl,
                    ["description"] = description,
                    ["dateModified"] = article.LastModifiedUtc == default ? null : article.LastModifiedUtc.ToString("O")
                }),
                PublicSeo.BreadcrumbJsonLd(
                    ("Help", PublicSeo.AbsoluteUrl(configuration, "/help")),
                    (article.Category, PublicSeo.AbsoluteUrl(configuration, article.CategoryUrl)),
                    (article.Title, canonicalUrl))
            ]
        });
        return View(new HelpCentreArticleViewModel
        {
            Article = article,
            RenderedHtml = markdown.Render(article.MarkdownContent),
            RelatedArticles = help.GetRelatedArticles(article)
        });
    }

    [HttpGet("/Help/Category/{category}")]
    public IActionResult LegacyCategory(string category)
    {
        var articles = help.GetByCategory(WebUtility.UrlDecode(category));
        var firstArticle = articles.FirstOrDefault();
        return firstArticle is null
            ? NotFound()
            : RedirectPermanent(firstArticle.CategoryUrl);
    }

    [HttpGet("/Help/Article/{key}")]
    public IActionResult LegacyArticle(string key)
    {
        var article = help.GetByContextKey(WebUtility.UrlDecode(key));
        return article is null
            ? View("ArticleNotFound", key)
            : RedirectPermanent(article.Url);
    }

    private bool IsCanonicalPath(string path) =>
        string.Equals(HttpContext.Request.Path.Value, path, StringComparison.Ordinal);

    private string PreserveQuery(string path) =>
        string.IsNullOrWhiteSpace(HttpContext.Request.QueryString.Value)
            ? path
            : $"{path}{HttpContext.Request.QueryString.Value}";

    private static string CategoryDescription(string category) =>
        $"Find PlotDirector help articles for {category.ToLowerInvariant()}, including practical guidance for organising story details, reviewing continuity, and keeping your novel on track.";
}
