import {
	LitElement,
	css,
	html,
	repeat,
	render,
	unsafeCSS,
	unsafeHTML,
	until,
} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import * as tfutils from './tf-utils.js';
import * as emojis from './emojis.js';
import {styles, generate_theme} from './tf-styles.js';
class TfMessageElement extends LitElement {
	static get properties() {
		return {
			whoami: {type: String},
			message: {type: Object},
			users: {type: Object},
			drafts: {type: Object},
			format: {type: String},
			blog_data: {type: String},
			expanded: {type: Object},
			channel: {type: String},
			channel_unread: {type: Number},
			recent_reactions: {type: Array},
			depth: {type: Number},
		};
	}
	static styles = styles;
	constructor() {
		super();
		let self = this;
		this.whoami = null;
		this.message = {};
		this.users = {};
		this.drafts = {};
		this.format = 'message';
		this.expanded = {};
		this.channel_unread = -1;
		this.recent_reactions = [];
		this.depth = 0;
	}
	connectedCallback() {
		super.connectedCallback();
		this._click_callback = this.document_click.bind(this);
		this._blob_stored = this.blob_stored.bind(this);
		document.body.addEventListener('mouseup', this._click_callback);
		window.addEventListener('blob-stored', this._blob_stored);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		window.removeEventListener('blob-stored', this._blob_stored);
		document.body.removeEventListener('mouseup', this._click_callback);
	}
	document_click(event) {
		let content = this.renderRoot.querySelector('.w3-dropdown-content');
		let target = event.target;
		if (content && !content.contains(target)) {
			content.classList.remove('w3-show');
		}
	}
	blob_stored(event) {
		let search = `/${event.detail.id}/view`;
		for (let img of this.shadowRoot.querySelectorAll('img')) {
			if (img.src.indexOf(search) != -1) {
				let src = img.src.split('?')[0];
				img.src = `${src}?${new Date().valueOf()}`;
			}
		}
	}
	show_reply() {
		let event = new CustomEvent('tf-draft', {
			bubbles: true,
			composed: true,
			detail: {
				id: this.message?.id,
				draft: {
					encrypt_to: this.message?.decrypted?.recps,
				},
			},
		});
		this.dispatchEvent(event);
	}
	discard_reply() {
		this.dispatchEvent(
			new CustomEvent('tf-draft', {
				bubbles: true,
				composed: true,
				detail: {id: this.id, draft: undefined},
			})
		);
	}
	show_reactions() {
		let modal = document.getElementById('reactions_modal');
		modal.users = this.users;
		modal.votes = this.message?.votes || [];
	}
	render_votes() {
		function normalize_expression(expression) {
			if (
				expression === 'Unlike' ||
				expression === 'unlike' ||
				expression == 'undig'
			) {
				return 'đ';
			} else if (expression === 'heart') {
				return 'â¤ī¸';
			} else if (
				(expression ?? '').split('').every((x) => x.charCodeAt(0) < 256)
			) {
				return 'đ';
			} else {
				return expression;
			}
		}
		if (this.message?.votes?.length) {
			return html` `;
		}
	}
	render_json(value) {
		let json = JSON.stringify(value, null, 2);
		return html`
			
${json} 
		`;
	}
	render_raw() {
		let raw = {
			id: this.message?.id,
			previous: this.message?.previous,
			author: this.message?.author,
			sequence: this.message?.sequence,
			timestamp: this.message?.timestamp,
			hash: this.message?.hash,
			content: this.message?.content,
			signature: this.message?.signature,
		};
		return this.render_json(raw);
	}
	vote(emoji) {
		let reaction = emoji;
		let message = this.message.id;
		tfrpc.rpc
			.appendMessage(this.whoami, {
				type: 'vote',
				vote: {
					link: message,
					value: 1,
					expression: reaction,
				},
			})
			.catch(function (error) {
				alert(error?.message);
			});
	}
	react(event) {
		emojis.picker(
			(x) => this.vote(x),
			null,
			this.whoami,
			this.recent_reactions
		);
	}
	show_image(link) {
		let div = document.createElement('div');
		div.style.left = 0;
		div.style.top = 0;
		div.style.width = '100%';
		div.style.height = '100%';
		div.style.position = 'fixed';
		div.style.background = '#000';
		div.style.zIndex = 100;
		div.style.display = 'grid';
		let img = document.createElement('img');
		img.src = link;
		img.style.maxWidth = '100vw';
		img.style.maxHeight = '100vh';
		img.style.display = 'block';
		img.style.margin = 'auto';
		img.style.objectFit = 'contain';
		img.style.width = '100vw';
		div.appendChild(img);
		function image_close(event) {
			document.body.removeChild(div);
			window.removeEventListener('keydown', image_close);
		}
		div.onclick = image_close;
		window.addEventListener('keydown', image_close);
		document.body.appendChild(div);
	}
	body_click(event) {
		if (event.srcElement.tagName == 'IMG') {
			this.show_image(event.srcElement.src);
		} else if (
			event.srcElement.tagName == 'DIV' &&
			event.srcElement.classList.contains('img_caption')
		) {
			let next = event.srcElement.nextSibling;
			if (next.style.display != 'none') {
				next.style.display = 'none';
			} else {
				next.style.display = 'block';
			}
		}
	}
	render_mention(mention) {
		if (!mention?.link || typeof mention.link != 'string') {
			return this.render_json(mention);
		} else if (
			mention?.link?.startsWith('&') &&
			mention?.type?.startsWith('image/')
		) {
			return html`
				
					 
			`;
		} else if (
			mention.link?.startsWith('&') &&
			mention.name?.startsWith('video:')
		) {
			return html`
				
					 
			`;
		} else if (
			mention.link?.startsWith('&') &&
			mention?.type === 'application/tildefriends'
		) {
			return html` đ ${mention.name} `;
		} else if (mention.link?.startsWith('%') || mention.link?.startsWith('@')) {
			return html` ${mention.name} `;
		} else if (mention.link?.startsWith('#')) {
			return html` ${mention.link} `;
		} else if (
			Object.keys(mention).length == 2 &&
			mention.link &&
			mention.name
		) {
			return html` ${mention.name} `;
		} else {
			return this.render_json(mention);
		}
	}
	render_mentions() {
		let mentions = this.message?.content?.mentions || [];
		mentions = mentions.filter(
			(x) =>
				this.message?.content?.text?.indexOf(
					typeof x === 'string' ? x : x.link
				) === -1
		);
		if (mentions.length) {
			let self = this;
			return html`
				
					Mentions 
					${mentions.map((x) => self.render_mention(x))}
				 
			`;
		}
	}
	total_child_messages(message) {
		if (!message.child_messages) {
			return 0;
		}
		let total = message.child_messages.length;
		for (let m of message.child_messages) {
			total += this.total_child_messages(m);
		}
		return total;
	}
	expanded_key() {
		return (
			this.message?.id || this.message?.messages?.map((x) => x.id).join(':')
		);
	}
	set_expanded(expanded, tag) {
		let key = this.expanded_key();
		this.dispatchEvent(
			new CustomEvent('tf-expand', {
				bubbles: true,
				composed: true,
				detail: {id: key + (tag || ''), expanded: expanded},
			})
		);
	}
	toggle_expanded(tag) {
		let key = this.expanded_key();
		this.set_expanded(!this.expanded[key + (tag || '')], tag);
	}
	is_expanded(tag) {
		let key = this.expanded_key();
		return this.expanded[key + (tag || '')];
	}
	render_children() {
		let self = this;
		if (this.message.child_messages?.length) {
			if (!this.expanded[this.expanded_key()]) {
				return html`
					 self.set_expanded(true)}
					>
						+ ${this.total_child_messages(this.message) + ' More'}
					 
				`;
			} else {
				return html` 
					${repeat(
						this.message.child_messages || [],
						(x) => x.id,
						(x) =>
							html`
								 `
					)}
					
						 self.set_expanded(false)}
						>
							Collapse
						 
					 
				 `;
			}
		} else {
			return undefined;
		}
	}
	mark_unread() {
		this.dispatchEvent(
			new CustomEvent('channelsetunread', {
				bubbles: true,
				composed: true,
				detail: {
					channel: this.channel,
					unread: this.message.rowid,
				},
			})
		);
	}
	render_channels() {
		let content = this.message?.content;
		if (this?.messsage?.decrypted?.type == 'post') {
			content = this.message.decrypted;
		}
		let channels = [];
		if (typeof content.channel === 'string') {
			channels.push(`#${content.channel}`);
		}
		if (Array.isArray(content.mentions)) {
			for (let mention of content.mentions) {
				if (typeof mention?.link === 'string' && mention.link.startsWith('#')) {
					channels.push(mention.link);
				}
			}
		}
		return channels.map((x) => html`
				
					%
				 
				
					View Message 
					
						Copy ID
					 
					${this.drafts[this.message?.id] === undefined
						? html`
								
									âŠī¸ Reply
								 
							`
						: undefined}
					
						đ React
					 
					${formats.map(
						([format, name]) => html`
							
 (this.format = format)}
							>
								${name}
							 
						`
					)}
				
 
			 
		`;
	}
	render_header() {
		let is_encrypted = this.message?.decrypted
			? html`đ `
			: typeof this.message?.content == 'string'
				? html`đ `
				: undefined;
		return html`
			
		`;
	}
	render_frame(inner) {
		return html`
			
			
				${inner}
			
		`;
	}
	render_small_frame(inner) {
		let self = this;
		return this.render_frame(html`
			${self.render_header()}
			${self.format == 'raw'
				? html`${self.render_raw()}
`
				: inner}
			${self.render_votes()}
			${(self.message.child_messages || []).map(
				(x) => html`
					
							
					`
				: undefined;
		return html`
			${reply}
			${this.render_children()} 
		`;
	}
	content_group_by_author() {
		let sorted = this.message.messages
			.map((x) => [
				x.author,
				x.content.following && x.content.blocking
					? 'is following and blocking'
					: x.content.following
						? 'is following'
						: x.content.blocking
							? 'is blocking'
							: x.content.blocking !== undefined
								? 'is no longer blocking'
								: x.content.following !== undefined
									? 'is no longer following'
									: '',
				x.content.contact,
				x,
			])
			.sort();
		let result = [];
		let last;
		let group;
		for (let row of sorted) {
			if (last && last[0] == row[0] && last[1] == row[1]) {
				group.push(row[2]);
			} else {
				if (group) {
					result.push({author: last[0], action: last[1], users: group});
				}
				last = row;
				group = [row[2]];
			}
		}
		if (group) {
			result.push({author: last[0], action: last[1], users: group});
		}
		return result;
	}
	channel_group_by_author() {
		let sorted = this.message.messages
			.map((x) => [
				x.author,
				x.content.subscribed ? 'subscribed to' : 'unsubscribed from',
				x.content.channel,
				x,
			])
			.sort();
		let result = [];
		let last;
		let group;
		for (let row of sorted) {
			if (last && last[0] == row[0] && last[1] == row[1]) {
				group.push(row[2]);
			} else {
				if (group) {
					result.push({author: last[0], action: last[1], channels: group});
				}
				last = row;
				group = [row[2]];
			}
		}
		if (group) {
			result.push({author: last[0], action: last[1], channels: group});
		}
		return result;
	}
	allow_unread() {
		return (
			this.channel == '@' ||
			(!this.channel.startsWith('@') && !this.channel.startsWith('%'))
		);
	}
	render_unread_icon() {
		return this.allow_unread() && this.message?.rowid >= this.channel_unread
			? html`âī¸`
			: undefined;
	}
	_render() {
		let content = this.message?.content;
		if (this.message?.decrypted?.type == 'post') {
			content = this.message.decrypted;
		}
		let class_background = this.class_background();
		let self = this;
		if (this.message?.type === 'contact_group') {
			if (this.expanded[this.expanded_key()]) {
				return this.render_frame(html`
					
						${this.message.messages.map(
							(x) =>
								html`
					 self.set_expanded(false)}
					>
						Collapse
					 
				`);
			} else {
				return this.render_frame(html`
					
						${this.content_group_by_author().map(
							(x) => html`
								
									
							`
						)}
					
 self.set_expanded(true)}
					>
						Expand
					 
				`);
			}
		} else if (this.message?.type === 'channel_group') {
			if (this.expanded[this.expanded_key()]) {
				return this.render_frame(html`
					
						${this.message.messages.map(
							(x) =>
								html`
					 self.set_expanded(false)}
					>
						Collapse
					 
				`);
			} else {
				return this.render_frame(html`
					
						${this.channel_group_by_author().map(
							(x) => html`
								
									
							`
						)}
					
 self.set_expanded(true)}
					>
						Expand
					 
				`);
			}
		} else if (this.message.placeholder) {
			return this.render_frame(
				html`
					
					${this.render_votes()}
					${(this.message.child_messages || []).map(
						(x) => html`
							
						`
					)}
				
 `
			);
		} else if (typeof content?.type === 'string') {
			if (content.type == 'about') {
				let name;
				let image;
				let description;
				if (content.name !== undefined) {
					name = html`Name:  ${content.name}
`;
				}
				if (content.image !== undefined) {
					image = html`
						
					`;
				}
				if (content.description !== undefined) {
					description = html`
						
							${unsafeHTML(tfutils.markdown(content.description))}
						 
					`;
				}
				let update =
					content.about == this.message.author
						? html`Updated profile.
`
						: html`
								Updated profile for
								
`;
				return this.render_small_frame(html`
					
						${update} ${name} ${image} ${description}
					 
				`);
			} else if (content.type == 'contact') {
				switch (this.format) {
					case 'message':
					default:
						return this.render_frame(html`
							
								
									
								${this.render_menu()} ${this.render_votes()}
								${this.render_actions()}
							
 
						`);
						break;
					case 'raw':
						return this.render_frame(html`
							${this.render_header()}
							${this.render_raw()}
							${this.render_votes()} ${this.render_actions()}
						
						`);
						break;
				}
			} else if (content.type == 'post') {
				let self = this;
				let body;
				switch (this.format) {
					case 'raw':
						body = this.render_raw();
						break;
					case 'md':
						body = html`${content.text}`;
						break;
					case 'message':
						body = unsafeHTML(tfutils.markdown(content.text));
						break;
					case 'decrypted':
						body = this.render_json(content);
						break;
				}
				let content_warning = html`
					 this.toggle_expanded(':cw')}
					>
						
${content.contentWarning}
						
							${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
						
					${body}
					${this.render_mentions()}
				`;
				let payload = content.contentWarning
					? self.expanded[(this.message.id || '') + ':cw']
						? html` ${content_warning} ${content_html} `
						: content_warning
					: content_html;
				return this.render_frame(html`
					${this.render_header()}
					${payload}
					${this.render_votes()} ${this.render_actions()}
				
				`);
			} else if (content.type === 'issue') {
				return this.render_frame(html`
					${this.render_header()} ${content.text} ${this.render_votes()}
					
						
							React
						 
						${this.render_children()}
					 
				`);
			} else if (content.type === 'blog') {
				let self = this;
				tfrpc.rpc.get_blob(content.blog).then(function (data) {
					self.blog_data = data;
				});
				let payload = this.expanded[(this.message.id || '') + ':blog']
					? html`
							${this.blog_data
								? unsafeHTML(tfutils.markdown(this.blog_data))
								: 'Loading...'}
						
`
					: undefined;
				let body;
				switch (this.format) {
					case 'raw':
						body = this.render_raw();
						break;
					case 'md':
						body = content.summary;
						break;
					case 'message':
						body = html`
							 self.toggle_expanded(':blog')}>
								
${content.title} 
								
									${content.summary} 
								 
							${body}
					${this.render_mentions()} ${this.render_votes()}
					${this.render_actions()}
				`);
			} else if (content.type === 'pub') {
				return this.render_small_frame(
					html` 
						
							
								đģ
								
							${content.address.host}:${content.address.port} 
						 `
				);
			} else if (content.type === 'channel') {
				return this.render_small_frame(html`
					
				`);
			} else if (typeof this.message.content == 'string') {
				if (this.message?.decrypted) {
					if (this.format == 'decrypted') {
						return this.render_small_frame(
							html`đ  ${this.render_json(
									this.message.decrypted
								)}`
						);
					} else {
						return this.render_small_frame(
							html`đ 
								${this.message.decrypted.type}
`
						);
					}
				} else {
					return this.render_small_frame();
				}
			} else {
				return this.render_small_frame(
					html``
				);
			}
		} else if (typeof this.message.content == 'string') {
			return this.render_small_frame();
		} else {
			return this.render_small_frame(this.render_raw());
		}
	}
	render() {
		return html`
			
			${this._render()}
		`;
	}
}
customElements.define('tf-message', TfMessageElement);