using System.Net.Mime;
using System.ServiceModel.Syndication;
using System.Text.Json.Serialization;
using System.Xml;
using Microsoft.AspNetCore.Mvc;
using PancakesWeb.Components.UI;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;

namespace PancakesWeb.Controllers;

[ApiController]
public class FeedController : ControllerBase
{
    [HttpGet("/feed.atom")]
    [Produces("application/atom+xml")]
    public ContentResult GetAtomFeed()
    {
        var feed = new SyndicationFeed
        {
            Title = new TextSyndicationContent("pancakes' blog"),
            Description = new TextSyndicationContent("🐈‍⬛"),
            Id = "https://pancakes.gay/feed.atom",
            BaseUri = new Uri("https://pancakes.gay/feed.atom"),
            Authors = { new SyndicationPerson("p@pancakes.gay", "pancakes", "https://pancakes.gay") },
            Items = BlogPosts.Posts.OrderByDescending(post => post.Published).Select(post =>
                new SyndicationItem(post.Title, SyndicationContent.CreateHtmlContent(post.Content),
                    new Uri($"https://pancakes.gay/{post.Slug}"), $"https://pancakes.gay/{post.Slug}",
                    new DateTimeOffset(post.Edited ?? post.Published))
                {
                    Copyright = post.Footer is BlogPosts.PostFooter.CcBy
                        ? new TextSyndicationContent(
                            $"{post.Title} © {post.Published.Year} by pancakes is licensed under CC BY 4.0")
                        : null,
                    PublishDate = new DateTimeOffset(post.Published),
                    Summary = new TextSyndicationContent(post.Description)
                }),
            Links =
            {
                SyndicationLink.CreateSelfLink(new Uri("https://pancakes.gay/feed.atom")),
                SyndicationLink.CreateAlternateLink(new Uri("https://pancakes.gay"), MediaTypeNames.Text.Html),
            }
        };

        var stringWriter = new StringWriter();
        var writer = new XmlTextWriter(stringWriter);
        feed.SaveAsAtom10(writer);

        return Content(stringWriter.ToString(), "application/atom+xml");
    }

    [HttpGet("/feed.json")]
    [Produces("application/feed+json", MediaTypeNames.Application.Json)]
    public JsonFeed GetJsonFeed() => new JsonFeed
    {
        Title = "pancakes' blog",
        HomePageUrl = "https://pancakes.gay",
        FeedUrl = "https://pancakes.gay/feed.json",
        Description = "🐈‍⬛",
        Icon = "https://pancakes.gay/icon.webp",
        Favicon = "https://pancakes.gay/favicon.ico",
        Authors =
        [
            new JsonFeedAuthor
            {
                Name = "pancakes",
                Url = "https://pancakes.gay",
                Avatar = "https://pancakes.gay/icon.webp"
            }
        ],
        Language = "en",
        Items = BlogPosts.Posts.OrderByDescending(post => post.Published).Select(post => new JsonFeedItem
        {
            Id = $"https://pancakes.gay/{post.Slug}",
            Url = $"https://pancakes.gay/{post.Slug}",
            Title = post.Title,
            ContentHtml = post.Content,
            Summary = post.Description,
            BannerImage = $"https://pancakes.gay/post-assets/{post.Slug}/{post.HeaderFilename}",
            DatePublished = post.Published,
            DateModified = post.Edited,
            Tags = null
        }).ToList()
    };

    public class JsonFeed
    {
        [J("version")] public string Version => "https://jsonfeed.org/version/1.1";
        [J("title")] public required string Title { get; set; }

        [J("home_page_url")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? HomePageUrl { get; set; }

        [J("feed_url")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? FeedUrl { get; set; }

        [J("description")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Description { get; set; }

        [J("icon")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Icon { get; set; }

        [J("favicon")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Favicon { get; set; }

        [J("authors")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public List<JsonFeedAuthor>? Authors { get; set; }

        [J("language")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Language { get; set; }

        [J("items")] public List<JsonFeedItem> Items { get; set; } = [];
    }

    public class JsonFeedAuthor
    {
        [J("name")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Name { get; set; }

        [J("url")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Url { get; set; }

        [J("avatar")]
        [JI(Condition = JsonIgnoreCondition.Never)]
        public string? Avatar { get; set; }
    }

    public class JsonFeedItem
    {
        [J("id")] public required string Id { get; set; }

        [J("url")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Url { get; set; }

        [J("title")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Title { get; set; }

        [J("content_html")] public required string ContentHtml { get; set; }

        [J("summary")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Summary { get; set; }

        [J("banner_image")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? BannerImage { get; set; }

        [J("date_published")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public DateTime? DatePublished { get; set; }

        [J("date_modified")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public DateTime? DateModified { get; set; }

        [J("tags")]
        [JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public List<string>? Tags { get; set; }
    }
}