import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js';

class TfNewsElement extends LitElement {
	static get properties() {
		return {
			whoami: {type: String},
			users: {type: Object},
			messages: {type: Array},
			following: {type: Array},
			drafts: {type: Object},
			expanded: {type: Object},
			channel: {type: String},
			channel_unread: {type: Number},
			recent_reactions: {type: Array},
			hash: {type: String},
		};
	}

	static styles = styles;

	constructor() {
		super();
		let self = this;
		this.whoami = null;
		this.users = {};
		this.messages = [];
		this.following = [];
		this.drafts = {};
		this.expanded = {};
		this.channel_unread = -1;
		this.recent_reactions = [];
	}

	process_messages(messages) {
		let self = this;
		let messages_by_id = {};

		console.log('processing', messages.length, 'messages');

		function ensure_message(id, rowid) {
			let found = messages_by_id[id];
			if (found) {
				return found;
			} else {
				let added = {
					rowid: rowid,
					id: id,
					placeholder: true,
					content: '"placeholder"',
					parent_message: undefined,
					child_messages: [],
					votes: [],
				};
				messages_by_id[id] = added;
				return added;
			}
		}

		function link_message(message) {
			if (message.content.type === 'vote') {
				let parent = ensure_message(message.content.vote.link, message.rowid);
				if (!parent.votes) {
					parent.votes = [];
				}
				parent.votes.push(message);
				message.parent_message = message.content.vote.link;
			} else if (message.content.type == 'post') {
				if (message.content.root) {
					if (typeof message.content.root === 'string') {
						let m = ensure_message(message.content.root, message.rowid);
						if (!m.child_messages) {
							m.child_messages = [];
						}
						m.child_messages.push(message);
						message.parent_message = message.content.root;
					} else {
						let m = ensure_message(message.content.root[0], message.rowid);
						if (!m.child_messages) {
							m.child_messages = [];
						}
						m.child_messages.push(message);
						message.parent_message = message.content.root[0];
					}
				}
			}
		}

		for (let message of messages) {
			message.votes = [];
			message.parent_message = undefined;
			message.child_messages = undefined;
		}

		for (let message of messages) {
			try {
				message.content = JSON.parse(message.content);
			} catch {}
			if (!messages_by_id[message.id]) {
				messages_by_id[message.id] = message;
				link_message(message);
			} else if (messages_by_id[message.id].placeholder) {
				let placeholder = messages_by_id[message.id];
				messages_by_id[message.id] = message;
				message.parent_message = placeholder.parent_message;
				message.child_messages = placeholder.child_messages;
				message.votes = placeholder.votes;
				if (
					placeholder.parent_message &&
					messages_by_id[placeholder.parent_message]
				) {
					let children =
						messages_by_id[placeholder.parent_message].child_messages;
					children.splice(children.indexOf(placeholder), 1);
					children.push(message);
				}
				link_message(message);
			}
		}

		return messages_by_id;
	}

	update_latest_subtree_timestamp(messages) {
		let latest = 0;
		for (let message of messages || []) {
			if (message.latest_subtree_timestamp === undefined) {
				message.latest_subtree_timestamp = Math.max(
					message.timestamp ?? 0,
					this.update_latest_subtree_timestamp(message.child_messages)
				);
			}
			latest = Math.max(latest, message.latest_subtree_timestamp);
		}
		return latest;
	}

	finalize_messages(messages_by_id) {
		function recursive_sort(messages, top) {
			if (messages) {
				if (top) {
					messages.sort(
						(a, b) => b.latest_subtree_timestamp - a.latest_subtree_timestamp
					);
				} else {
					messages.sort((a, b) => a.timestamp - b.timestamp);
				}
				for (let message of messages) {
					recursive_sort(message.child_messages, false);
				}
				return messages.map((x) => Object.assign({}, x));
			} else {
				return {};
			}
		}

		let roots = Object.values(messages_by_id).filter((x) => !x.parent_message);
		this.update_latest_subtree_timestamp(roots);
		return recursive_sort(roots, true);
	}

	group_following(messages) {
		let result = [];
		let group = [];
		for (let message of messages) {
			if (message?.content?.type === 'contact') {
				group.push(message);
			} else {
				if (group.length == 1) {
					result.push(group[0]);
					group = [];
				} else if (group.length > 1) {
					result.push({
						rowid: Math.max(...group.map((x) => x.rowid)),
						type: 'contact_group',
						messages: group,
					});
					group = [];
				}
				result.push(message);
			}
		}
		if (group.length == 1) {
			result.push(group[0]);
			group = [];
		} else if (group.length > 1) {
			result.push({
				rowid: Math.max(...group.map((x) => x.rowid)),
				type: 'contact_group',
				messages: group,
			});
		}
		return result;
	}

	unread_allowed() {
		return !this.hash?.startsWith('#%') && !this.hash?.startsWith('#@');
	}

	load_and_render(messages) {
		let messages_by_id = this.process_messages(messages);
		let final_messages = this.group_following(
			this.finalize_messages(messages_by_id)
		);
		let unread_rowid = -1;
		if (this.unread_allowed()) {
			for (let message of final_messages) {
				if (message.rowid >= this.channel_unread) {
					unread_rowid = message.rowid;
				}
			}
		}
		return html`
			<div>
				${repeat(
					final_messages,
					(x) => x.id,
					(x) => html`
						<tf-message
							.message=${x}
							whoami=${this.whoami}
							.users=${this.users}
							.drafts=${this.drafts}
							.expanded=${this.expanded}
							collapsed="true"
							channel=${this.channel}
							channel_unread=${this.channel_unread}
							.recent_reactions=${this.recent_reactions}
						></tf-message>
						${x.rowid == unread_rowid
							? html`<div style="display: flex; flex-direction: row">
									<div
										style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
									></div>
									<button
										style="color: #f00; padding: 8px"
										class="w3-button"
										@click=${() =>
											this.dispatchEvent(
												new Event('mark_all_read', {
													bubbles: true,
													composed: true,
												})
											)}
									>
										unread
									</button>
									<div
										style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
									></div>
								</div>`
							: undefined}
					`
				)}
			</div>
		`;
	}

	render() {
		return this.load_and_render(this.messages || []);
	}
}

customElements.define('tf-news', TfNewsElement);
