using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using Markdig;
using Markdig.Extensions.Yaml;
using Markdig.Renderers;
using Markdig.Syntax;
using Microsoft.AspNetCore.Mvc.RazorPages;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace zotanpw.Pages;

public class BlogModel : PageModel {
	public static readonly List<BlogPost> Posts = new();

	static BlogModel() {
		foreach (var file in Directory.EnumerateFiles("Posts"))
			if (file.EndsWith(".md"))
				Posts.Add(new BlogPost(Path.GetFileNameWithoutExtension(file)));

		Posts = Posts.OrderByDescending(p => p.PublishedOn).ToList();
	}

	public void OnGet() { }

	public class BlogPost {
		public readonly string Shorthand;
		public          string Content = "";

		public DateOnly PublishedOn;
		public int      ReadTimeMinutes;
		public string   Title = null!;

		public BlogPost(string shorthand) {
			Shorthand = shorthand;
			UpdateContentAndMetadata();
		}

		public void UpdateContentAndMetadata() {
			var markdownText = System.IO.File.ReadAllText($"Posts/{Shorthand}.md");

			var parsed = ParseBlogPost(markdownText);
			Title           = parsed.metadata.Title!;
			PublishedOn     = parsed.metadata.Date;
			ReadTimeMinutes = Regex.Matches(markdownText, @"\b\w+\b").Count / 150;
			Content         = parsed.html;
		}

		private static (PostMetadata metadata, string html) ParseBlogPost(string markdown) {
			var yaml = "";

			var pipeline = new MarkdownPipelineBuilder().UseGenericAttributes().UseYamlFrontMatter().UseAutoIdentifiers().Build();
			var writer   = new StringWriter();
			var renderer = new HtmlRenderer(writer);
			pipeline.Setup(renderer);

			var document  = Markdown.Parse(markdown, pipeline);
			var yamlBlock = document.Descendants<YamlFrontMatterBlock>().FirstOrDefault();

			if (yamlBlock != null)
				yaml = markdown.Substring(yamlBlock.Span.Start, yamlBlock.Span.Length);

			renderer.Render(document);
			writer.Flush();
			var html = writer.ToString();

			var yamlDeserializer = new DeserializerBuilder().WithNamingConvention(LowerCaseNamingConvention.Instance).Build();
			var metadata         = yamlDeserializer.Deserialize<PostMetadata>(yaml);

			return (metadata, html);
		}

		[SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")]
		private class PostMetadata {
			#pragma warning disable CS0649
			public string?  Title;
			public DateOnly Date;
			#pragma warning restore CS0649
		}
	}
}
