using System.Text;
using System.Xml;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PlotLine.Models;
using PlotLine.Services;

namespace PlotLine.Controllers;

[AllowAnonymous]
public sealed class SitemapController(IHelpService help, IConfiguration configuration) : Controller
{
    [HttpGet("/sitemap.xml")]
    public IActionResult Index()
    {
        var urls = new List<SitemapUrl>
        {
            new("/", "weekly", "1.0"),
            new("/features", "weekly", "0.9"),
            new("/pricing", "weekly", "0.8"),
            new("/help", "weekly", "0.7"),
            new("/about", "monthly", "0.6"),
            new("/contact", "monthly", "0.5"),
            new("/privacy", "yearly", "0.3"),
            new("/terms", "yearly", "0.3")
        };

        var articles = help.GetAllArticles();
        urls.AddRange(articles
            .Where(article => !string.IsNullOrWhiteSpace(article.CategorySlug))
            .GroupBy(article => article.CategorySlug, StringComparer.OrdinalIgnoreCase)
            .OrderBy(group => group.Key, StringComparer.OrdinalIgnoreCase)
            .Select(group => new SitemapUrl(
                $"/help/{group.Key}",
                "monthly",
                "0.6",
                group.Max(article => article.LastModifiedUtc))));

        urls.AddRange(articles
            .Where(article => !string.IsNullOrWhiteSpace(article.CategorySlug) && !string.IsNullOrWhiteSpace(article.Slug))
            .OrderBy(article => article.CategorySlug, StringComparer.OrdinalIgnoreCase)
            .ThenBy(article => article.Slug, StringComparer.OrdinalIgnoreCase)
            .Select(article => new SitemapUrl(
                article.Url,
                "monthly",
                "0.5",
                article.LastModifiedUtc)));

        return Content(BuildXml(urls), "application/xml", Encoding.UTF8);
    }

    private string BuildXml(IEnumerable<SitemapUrl> urls)
    {
        var settings = new XmlWriterSettings
        {
            Encoding = new UTF8Encoding(false),
            Indent = true,
            OmitXmlDeclaration = false
        };
        using var writer = new Utf8StringWriter();
        using var xml = XmlWriter.Create(writer, settings);
        xml.WriteStartDocument();
        xml.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");

        foreach (var url in urls)
        {
            xml.WriteStartElement("url");
            xml.WriteElementString("loc", PublicSeo.AbsoluteUrl(configuration, url.Path));
            if (url.LastModifiedUtc is DateTime lastModifiedUtc && lastModifiedUtc != default)
            {
                xml.WriteElementString("lastmod", lastModifiedUtc.ToString("yyyy-MM-dd"));
            }

            xml.WriteElementString("changefreq", url.ChangeFrequency);
            xml.WriteElementString("priority", url.Priority);
            xml.WriteEndElement();
        }

        xml.WriteEndElement();
        xml.WriteEndDocument();
        xml.Flush();
        return writer.ToString();
    }

    private sealed record SitemapUrl(string Path, string ChangeFrequency, string Priority, DateTime? LastModifiedUtc = null);

    private sealed class Utf8StringWriter : StringWriter
    {
        public override Encoding Encoding => Encoding.UTF8;
    }
}
