//! atproto-static-web   A simple web viewer for AT Proto.
//! Copyright (C) 2026  AverageHelper
//!
//! This program is free software: you can redistribute it and/or modify
//! it under the terms of the GNU General Public License as published by
//! the Free Software Foundation, either version 3 of the License, or
//! (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program.  If not, see <https://www.gnu.org/licenses/>.

use crate::xrpc::get_post_thread::{Facet, Feature, PostRecord};
use core::ops::Range;
use maud::{Markup, html};
use url::Url;

pub fn rich_text(post_record: &PostRecord) -> Markup {
	#[allow(clippy::needless_as_bytes)]
	let total_len = post_record.text.as_bytes().len();

	let mut facets: Vec<&Facet> = post_record.facets.iter().collect();

	// Put our starts in order
	facets.sort_by(|a, b| a.index.byte_start.cmp(&b.index.byte_start));

	// Filter out invalid facets
	let mut contiguous_facets: Vec<(Range<usize>, &Facet)> = Vec::with_capacity(facets.len());
	let mut current_end: usize = 0;

	for facet in facets {
		// skip indices too large to use
		let byte_start: usize = match facet.index.byte_start.try_into() {
			Ok(i) => i,
			Err(_) => continue,
		};
		let byte_end: usize = match facet.index.byte_end.try_into() {
			Ok(i) => i,
			Err(_) => continue,
		};

		// skip empty facets
		if byte_end <= byte_start {
			continue;
		}

		// skip facets that start after the string ends
		if byte_start >= total_len {
			continue;
		}

		// skip overlapping facets
		if byte_start < current_end || byte_end < current_end {
			continue;
		}

		current_end = byte_end;
		contiguous_facets.push((byte_start..byte_end, facet));
	}

	// Create markup from facets
	let mut text = post_record.text.bytes();
	let mut text_annotated: Vec<Markup> = Vec::with_capacity(post_record.facets.len() * 2);

	// insert text before facets, if any
	let byte_start = match contiguous_facets.first() {
		Some((range, _)) => range.start,
		None => total_len, // no facets, so insert whole text
	};
	if byte_start > 0 {
		let mut text_bytes: Vec<u8> = Vec::with_capacity(byte_start);
		for _ in 0..byte_start {
			match text.next() {
				Some(t) => text_bytes.push(t),
				None => break,
			}
		}
		// If the block splits a UTF-8 grapheme, we refuse to render any rich text.
		match str::from_utf8(&text_bytes) {
			Err(_) => return html! { (post_record.text) },
			Ok(text) => text_annotated.push(html! { (text) }),
		}
	}

	// insert faceted text
	let mut facets = contiguous_facets.iter().peekable();
	while let Some((range, facet)) = facets.next() {
		// insert faceted text
		let mut text_bytes: Vec<u8> = Vec::with_capacity(range.len());
		for _ in range.start..range.end {
			match text.next() {
				Some(t) => text_bytes.push(t),
				None => break,
			}
		}
		match str::from_utf8(&text_bytes) {
			Err(_) => return html! { (post_record.text) },
			Ok(text) => {
				let markup = match facet.features.first() {
					None => html! { (text) }, // no features = plaintext!
					Some(Feature::Link { uri }) => match Url::parse(text) {
						Err(url::ParseError::RelativeUrlWithoutBase) => {
							match Url::parse(&format!("{}://{text}", uri.scheme())) {
								Ok(text_url) if &text_url == uri => html! {
									a href=(uri) { (text) } // text + scheme matches url = no title needed!
								},
								Ok(_) | Err(_) => html! {
									a href=(uri) title=(uri) { (text) } // final url should go in the title
								},
							}
						}
						Ok(text_url) if &text_url == uri => html! {
							a href=(uri) { (text) } // text matches url = no title needed!
						},
						Ok(_) | Err(_) => html! {
							a href=(uri) title=(uri) { (text) } // final url should go in the title
						},
					},
					Some(Feature::Mention { did }) => html! {
						a href=(["/profile/", &did.to_string()].concat()) { (text) }
					},
					Some(Feature::Tag { tag }) => html! {
						a href=(["/hashtag/", tag].concat()) { (text) }
					},
				};
				text_annotated.push(markup);
			}
		}

		// insert intervening text
		if let Some((range_2, _)) = facets.peek() {
			let mut text_bytes: Vec<u8> = Vec::with_capacity(range.len());
			for _ in range.end..range_2.start {
				match text.next() {
					Some(t) => text_bytes.push(t),
					None => break,
				}
			}
			match str::from_utf8(&text_bytes) {
				Err(_) => return html! { (post_record.text) },
				Ok(text) => text_annotated.push(html! { (text) }),
			}
		}
	}

	// insert text after facets, if any
	if let Some((range, _)) = contiguous_facets.last()
		&& range.end < total_len
	{
		let mut text_bytes: Vec<u8> = Vec::with_capacity(total_len - range.end);
		for _ in range.end.. {
			match text.next() {
				Some(t) => text_bytes.push(t),
				None => break,
			}
		}
		match str::from_utf8(&text_bytes) {
			Err(_) => return html! { (post_record.text) },
			Ok(text) => text_annotated.push(html! { (text) }),
		}
	}

	html! {
		@for markup in text_annotated { (markup) }
	}
}

// MARK: - Tests

#[cfg(test)]
mod tests {
	use super::*;
	use crate::{
		atproto::DecentralizedIdentifier,
		xrpc::{
			get_post_thread::{ByteSlice, Facet},
			validations::LimitedString,
		},
	};
	use url::Url;
	use url_static::url;

	impl Default for PostRecord {
		fn default() -> Self {
			Self {
				text: Default::default(),
				facets: Vec::new(),
				langs: Vec::new(),
				created_at: chrono::Utc::now(),
			}
		}
	}

	impl ByteSlice {
		const fn new(byte_start: u64, byte_end: u64) -> Self {
			Self {
				byte_start,
				byte_end,
			}
		}
	}

	impl Feature {
		const fn link(uri: Url) -> Self {
			Self::Link { uri }
		}

		const fn mention(did: DecentralizedIdentifier) -> Self {
			Self::Mention { did }
		}

		const fn tag(tag: LimitedString<640, 64>) -> Self {
			Self::Tag { tag }
		}
	}

	#[test]
	fn test_empty_string_for_empty_record() {
		let record = PostRecord::default();
		let result = rich_text(&record);
		assert_eq!(result.0, "");
	}

	#[test]
	fn test_plain_text() {
		let record = PostRecord {
			text: "Lorem ipsum".try_into().unwrap(),
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "Lorem ipsum");
	}

	#[test]
	fn test_empty_string_for_facet_start_beyond_empty_string_end() {
		let facet = Facet {
			index: ByteSlice::new(0, 1),
			features: vec![Feature::link(url!("http://localhost"))],
		};
		let record = PostRecord {
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "");
	}

	#[test]
	fn test_plain_text_for_facet_start_beyond_string_end() {
		let facet = Facet {
			index: ByteSlice::new(1, 2),
			features: vec![Feature::link(url!("http://localhost"))],
		};
		let record = PostRecord {
			text: "f".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "f");
	}

	#[test]
	fn test_plain_text_for_empty_facet() {
		let facet = Facet {
			index: ByteSlice::new(0, 0),
			features: vec![Feature::link(url!("http://localhost"))],
		};
		let record = PostRecord {
			text: "f".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "f");
	}

	#[test]
	fn test_plain_text_for_facet_with_negative_length() {
		let facet = Facet {
			index: ByteSlice::new(1, 0),
			features: vec![Feature::link(url!("http://localhost"))],
		};
		let record = PostRecord {
			text: "yo".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "yo");
	}

	#[test]
	fn test_closes_pending_end_tags_for_facet_end_beyond_string_end() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 2),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "f".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href=(uri) title=(uri) { "f" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_link_with_short_text() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 1),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "a".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, html! { a href=(uri) title=(uri) { "a" } }.0);
	}

	#[test]
	fn test_link_with_long_grapheme() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 3),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あ".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, html! { a href=(uri) title=(uri) { "あ" } }.0);
	}

	#[test]
	fn test_plain_text_for_splitting_long_grapheme_at_start() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 1),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あ".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あ");
	}

	#[test]
	fn test_plain_text_for_splitting_long_grapheme_in_middle() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(1, 2),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あ".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あ");
	}

	#[test]
	fn test_plain_text_for_splitting_long_grapheme_at_end() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(2, 3),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あ".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あ");
	}

	#[test]
	fn test_link_with_mixed_length_graphemes() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 3),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(
			result.0,
			html! { a href=(uri) title=(uri) { "あ" } "www" }.0
		);
	}

	#[test]
	fn test_rich_text_with_mixed_length_graphemes() {
		let uri = url!("http://localhost");
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 3),
					features: vec![Feature::link(uri.clone())],
				},
				Facet {
					index: ByteSlice::new(3, 6),
					features: vec![Feature::link(uri.clone())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(
			result.0,
			html! {
				a href=(uri) title=(uri) { "あ" }
				a href=(uri) title=(uri) { "www" }
			}
			.0
		);
	}

	#[test]
	fn test_plain_text_for_only_facet_splitting_mixed_length_graphemes_at_start() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(0, 1),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_plain_text_for_only_facet_splitting_mixed_length_graphemes_in_middle() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(1, 2),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_plain_text_for_only_facet_splitting_mixed_length_graphemes_at_end() {
		let uri = url!("http://localhost");
		let facet = Facet {
			index: ByteSlice::new(2, 3),
			features: vec![Feature::link(uri.clone())],
		};
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![facet],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_plain_text_for_one_facet_splitting_mixed_length_graphemes_at_start() {
		let uri = url!("http://localhost");
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 1),
					features: vec![Feature::link(uri.clone())],
				},
				Facet {
					index: ByteSlice::new(3, 6),
					features: vec![Feature::link(uri.clone())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_plain_text_for_one_facet_splitting_mixed_length_graphemes_in_middle() {
		let uri = url!("http://localhost");
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(1, 2),
					features: vec![Feature::link(uri.clone())],
				},
				Facet {
					index: ByteSlice::new(3, 6),
					features: vec![Feature::link(uri.clone())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_plain_text_for_one_facet_splitting_mixed_length_graphemes_at_end() {
		let uri = url!("http://localhost");
		let record = PostRecord {
			text: "あwww".try_into().unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(2, 3),
					features: vec![Feature::link(uri.clone())],
				},
				Facet {
					index: ByteSlice::new(3, 6),
					features: vec![Feature::link(uri.clone())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		assert_eq!(result.0, "あwww");
	}

	#[test]
	fn test_rich_text_with_initial_facet() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![Facet {
				index: ByteSlice::new(0, 20),
				features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
			}],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head" }
			" is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy"
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_with_middle_facet() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![Facet {
				index: ByteSlice::new(45, 67),
				features: vec![Feature::mention(
					"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
				)],
			}],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			"Hello From Halo Head is a pretty good comic. "
			a href="/profile/did:plc:6aguc47fjvr4oyfvwver7ifp" { "@batshaped.bsky.social" }
			" does a great job with it\n\n#traumedy"
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_with_trailing_facet() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![Facet {
				index: ByteSlice::new(94, 103),
				features: vec![Feature::tag("traumedy".try_into().unwrap())],
			}],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 20),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(45, 67),
					features: vec![Feature::mention(
						"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
					)],
				},
				Facet {
					index: ByteSlice::new(94, 103),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head" }
			" is a pretty good comic. "
			a href="/profile/did:plc:6aguc47fjvr4oyfvwver7ifp" { "@batshaped.bsky.social" }
			" does a great job with it\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_in_reverse() {
		let mut facets = vec![
			Facet {
				index: ByteSlice::new(0, 20),
				features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
			},
			Facet {
				index: ByteSlice::new(45, 67),
				features: vec![Feature::mention(
					"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
				)],
			},
			Facet {
				index: ByteSlice::new(94, 103),
				features: vec![Feature::tag("traumedy".try_into().unwrap())],
			},
		];
		facets.reverse();
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets,
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head" }
			" is a pretty good comic. "
			a href="/profile/did:plc:6aguc47fjvr4oyfvwver7ifp" { "@batshaped.bsky.social" }
			" does a great job with it\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_duplicate_facets() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 20),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(0, 20),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(45, 67),
					features: vec![Feature::mention(
						"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
					)],
				},
				Facet {
					index: ByteSlice::new(94, 103),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
				Facet {
					index: ByteSlice::new(94, 103),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head" }
			" is a pretty good comic. "
			a href="/profile/did:plc:6aguc47fjvr4oyfvwver7ifp" { "@batshaped.bsky.social" }
			" does a great job with it\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_duplicate_similar_facets() {
		let record = PostRecord {
			text:
				"Hello From Halo Head is a pretty good comic. @batshaped.bsky.social does a great job with it\n\n#traumedy".try_into().unwrap()
			,
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 20),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(0, 20),
					features: vec![Feature::link(url!("https://halo-head.com/"))],
				},
				Facet {
					index: ByteSlice::new(45, 67),
					features: vec![Feature::mention(
						"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
					)],
				},
				Facet {
					index: ByteSlice::new(94, 103),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
				Facet {
					index: ByteSlice::new(94, 103),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head" }
			" is a pretty good comic. "
			a href="/profile/did:plc:6aguc47fjvr4oyfvwver7ifp" { "@batshaped.bsky.social" }
			" does a great job with it\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_eclipsed_similar_facets() {
		// e.g. "<a>foo <a>bar baz</a> bin</a>" ~> "<a>foo bar baz bin</a>"
		let record = PostRecord {
			text: "Hello From Halo Head by @batshaped.bsky.social is a great comic\n\n#traumedy"
				.try_into()
				.unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 46),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(24, 46),
					features: vec![Feature::mention(
						"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
					)],
				},
				Facet {
					index: ByteSlice::new(65, 74),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head by @batshaped.bsky.social" }
			" is a great comic\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_deeply_nested_eclipsed_similar_facets() {
		// e.g. "<a>foo <a><a>bar</a> baz</a> bin</a>" ~> "<a>foo bar baz bin</a>"
		let record = PostRecord {
			text: "Hello From Halo Head by @batshaped.bsky.social is a great comic\n\n#traumedy"
				.try_into()
				.unwrap(),
			facets: vec![
				Facet {
					index: ByteSlice::new(0, 46),
					features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
				},
				Facet {
					index: ByteSlice::new(11, 20),
					features: vec![Feature::link(url!("https://halo-head.com/"))],
				},
				Facet {
					index: ByteSlice::new(11, 46),
					features: vec![Feature::mention(
						"did:plc:6aguc47fjvr4oyfvwver7ifp".parse().unwrap(),
					)],
				},
				Facet {
					index: ByteSlice::new(65, 74),
					features: vec![Feature::tag("traumedy".try_into().unwrap())],
				},
			],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			a href="http://hellofromhalohead.com/" title="http://hellofromhalohead.com/" { "Hello From Halo Head by @batshaped.bsky.social" }
			" is a great comic\n\n"
			a href="/hashtag/traumedy" { "#traumedy" }
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_title_for_clear_links() {
		let record = PostRecord {
			text: "you should visit http://hellofromhalohead.com :3"
				.try_into()
				.unwrap(),
			facets: vec![Facet {
				index: ByteSlice::new(17, 45),
				features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
			}],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			"you should visit "
			a href="http://hellofromhalohead.com/" { "http://hellofromhalohead.com" }
			" :3"
		};
		assert_eq!(result.0, expected.0);
	}

	#[test]
	fn test_rich_text_skips_title_for_clear_links_without_scheme() {
		let record = PostRecord {
			text: "you should visit hellofromhalohead.com :3"
				.try_into()
				.unwrap(),
			facets: vec![Facet {
				index: ByteSlice::new(17, 38),
				features: vec![Feature::link(url!("http://hellofromhalohead.com"))],
			}],
			..Default::default()
		};
		let result = rich_text(&record);
		let expected = html! {
			"you should visit "
			a href="http://hellofromhalohead.com/" { "hellofromhalohead.com" }
			" :3"
		};
		assert_eq!(result.0, expected.0);
	}

	// TODO: Deobfuscare deceptive URLs (need to keep a list of TLDs and check manually if the text is a URL, because otherwise _every_ link is potentially deceptive! That or we only bother if the text itself contains a scheme, which might be kinda rare...)
	// TODO: Try to deobfuscate links that try to look like a different URL than where they actually go
	// TODO: Consider also changing HTTP links to HTTPS; let browsers fall back properly if that's wrong.
	// TODO: Test multiple features in a slice; see about getting slice indices out of order
	// TODO: Formatting tags should be permitted inside anchors, if that ever gets implemented.) (e.g. "<a>foo <strong>bar baz</strong> bin</a>" is valid)
	// TODO: Skip deeply-nested eclipsed facets of different kinds (e.g. "<a>foo bar <strong>bar <a>baz</a></strong> bin</a>" ~> "<a>foo bar <strong>bar baz</strong> bin</a>")
	// TODO: Plain text for partially overlapping facets of different kinds (e.g. "<a>foo bar <strong>baz</a> bin</strong>" ~> "foo bar baz bin")
	// TODO: Plain text for partially overlapping facets of different kinds, even deeply nested (e.g. "<a>foo bar <strong>b<a>az</a> bin</a></strong>" ~> "foo bar baz bin")
	// TODO: Plain text for eclipsed similar facets and partially overlapping facets of different kinds
}
