//! atproto-static-web   A simple web viewer for AT Proto.
//! Copyright (C) 2025  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::{
	server::lang::{Lang, tr},
	templates,
	xrpc::get_post_thread::{EmbedView, PostView, ThreadViewPost},
};
use maud::{Markup, PreEscaped, html};

pub fn regular(lang: Lang, is_pinned: bool, is_parent: bool, post: &PostView) -> Markup {
	let author = &post.author;
	let handle = format!("@{}", author.handle);
	let display_name: &str = match &author.display_name {
		None => &handle,
		Some(d) => d,
	};
	let profile_uri = format!("/profile/{}", author.did);
	let created_at = post.record.created_at;
	let since_now = {
		let since: i64 = chrono::Utc::now()
			.signed_duration_since(created_at)
			.as_seconds_f64()
			.floor() as i64;
		const MIN: i64 = 60; // 60s
		const HOUR: i64 = MIN * 60; // 60m
		const DAY: i64 = HOUR * 24; // 24h
		const MONTH: i64 = DAY * 30; // 30d
		const YEAR: i64 = MONTH * 12; // 12mo
		if since < 0 {
			tr!(lang, "since_now.future") // negative seconds since post
		} else if since < MIN {
			tr!(lang, "since_now.one_minute_ago") // about 1m since post
		} else if since < HOUR {
			tr!(lang, "since_now.minutes", m = since / MIN) // less than 1h since post
		} else if since < DAY {
			tr!(lang, "since_now.hours", h = since / HOUR) // less than 1d since post
		} else if since < MONTH {
			tr!(lang, "since_now.days", d = since / DAY) // less than 1mo since post
		} else if since < YEAR {
			tr!(lang, "since_now.months", mo = since / MONTH) // less than 1y since post
		} else {
			tr!(lang, "since_now.years", y = since / YEAR)
		}
	};

	html! {
		article class="post" {
			@if is_pinned {
				aside aria-label=(tr!(lang, "post.pinned_label")) class="pinned" {
					// TODO: Clean this up some
					div style="float:left; height: 4px; width:42px" {} // spacer, same size as the avatar
					span style="margin-left: -11px" { "🖈 " } // negative margin the width of the icon
					span { " "(tr!(lang, "post.pinned")) }
				}
			}
			div class="horizontal" {
				aside {
					a aria-label=(tr!(lang, "post.avatar_label")) href=(profile_uri) {
						@if let Some(avatar) = &author.avatar {
							img class="avatar" src=(avatar) alt="" width="42" height="42";
						} @else {
							img class="avatar" src="" alt="" width="42" height="42";
						}
					}
					@if is_parent {
						div aria-hidden class="thread-line" {} // visually indicates a thread
					}
				}
				section {
					header class="profile" {
						h2 {
							a href=(profile_uri) { (display_name) }
							a class="handle" href=(profile_uri) { (handle) }
						}
						span class="separator" { "·" }
						a class="time" href=(post.uri.to_local_uri()) {
							// TODO: Format for locale
							time datetime=(created_at.format("%F %RZ")) title=(created_at.format("%B %-d, %Y at %R UTC")) {
								(since_now)
							}
						}
					}
					blockquote {
						(templates::rich_text::rich_text(&post.record))
					}
					@if let Some(ref embed) = post.embed {
						(embeds(lang, embed))
					}
					(stats(lang, post))
				}
			}
		}
	}
}

pub fn focus(lang: Lang, thread: &ThreadViewPost) -> Markup {
	let author = &thread.post.author;
	let handle = format!("@{}", author.handle);
	let display_name: &str = match &author.display_name {
		None => &handle,
		Some(d) => d,
	};
	let profile_uri = format!("/profile/{}", author.did);
	let created_at = thread.post.record.created_at;

	html! {
		article class="post primary" {
			header class="profile" {
				a aria-label=(tr!(lang, "post.avatar_label")) href=(profile_uri) {
					@if let Some(avatar) = &author.avatar {
						img class="avatar" src=(avatar) alt="" width="42" height="42";
					} @else {
						img class="avatar" src="" alt="" width="42" height="42";
					}
				}
				section class="user" {
					h2 { a href=(profile_uri) { (display_name) } }
					a class="handle" href=(profile_uri) { (handle) }
				}
			}
			blockquote {
				(templates::rich_text::rich_text(&thread.post.record))
			}
			@if let Some(ref embed) = thread.post.embed {
				(embeds(lang, embed))
			}
			aside class="time" {
				p {
					a href=(thread.post.uri.to_local_uri()) {
						time datetime=(created_at.format("%F %RZ")) {
							// TODO: Format for locale
							(created_at.format("%b %-d, %Y at %R UTC"))
						}
					}
				}
			}
			(stats(lang, &thread.post))
		}
	}
}

fn embeds(lang: Lang, embed: &EmbedView) -> Markup {
	// TODO: Labels to ensure we hide NSFW stuff correctly
	html! {
		section class="embeds" {
			@match embed {
				EmbedView::Images { images } => {
					@for image in images.as_ref() {
						@if image.alt.is_empty() {
							img src=(image.fullsize) alt=(tr!(lang, "post.image.default_alt")) loading="lazy";
						} @else {
							img src=(image.fullsize) alt=(image.alt) loading="lazy";
						}
					}
				},
				EmbedView::Video { playlist, thumbnail, alt } => {
					@if let Some(thumbnail) = thumbnail {
						video controls preload="metadata" aria-description=(alt) poster=(thumbnail) {
							source src=(playlist) type="application/x-mpegURL";
						}
					} @else {
						video controls preload="metadata" aria-description=(alt) {
							source src=(playlist) type="application/x-mpegURL";
						}
					}
				}
				EmbedView::External { external } => @if let Some(domain) = external.uri.domain() {
					a rel="external noopener noreferrer" href=(external.uri) {
						@if let Some(thumb) = &external.thumb {
							img src=(thumb) alt="" loading="lazy";
						}
						h3 { (external.title) }
						p { (external.description) }
						p class="subtext" { (domain) } // domain is always required; we don't embed other types of URI
					}
				}
			}
		}
	}
}

fn stats(lang: Lang, post: &PostView) -> Markup {
	html! {
		aside class="post stats" {
			span class="item" {
				span aria-label=(tr!(lang, "post.stats.replies_label")) { (PreEscaped(include_str!("icons/speech-bubble.svg"))) }
				span class="value" {
					@if let Some(replies) = post.reply_count {
						(replies)
					} @else {
						(tr!(lang, "post.stats.unknown_value"))
					}
				}
			}
			span class="item" {
				span aria-label=(tr!(lang, "post.stats.reposts_label")) { (PreEscaped(include_str!("icons/repost.svg"))) }
				span class="value" {
					@if let Some(reposts) = post.repost_count {
						(reposts)
					} @else {
						(tr!(lang, "post.stats.unknown_value"))
					}
				}
			}
			span class="item" {
				span aria-label=(tr!(lang, "post.stats.likes_label")) { (PreEscaped(include_str!("icons/heart.svg"))) }
				span class="value" {
					@if let Some(likes) = post.like_count {
						(likes)
					} @else {
						(tr!(lang, "post.stats.unknown_value"))
					}
				}
			}
			span class="item" {
				details {
					summary aria-label=(tr!(lang, "post.stats.menu_label")) { (PreEscaped(include_str!("icons/post-menu.svg"))) }
					menu {
						li { "AT URI: "(post.uri) } // TODO: i18n
					}
				}
			}
		}
	}
}
