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

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

	static styles = styles;

	constructor() {
		super();
		let self = this;
		this.whoami = null;
		this.users = {};
		this.hash = '#';
		this.following = [];
		this.drafts = {};
		this.expanded = {};
		this.start_time = new Date().valueOf() - 24 * 60 * 60 * 1000;
	}

	async fetch_messages() {
		if (this.hash.startsWith('#@')) {
			let r = await tfrpc.rpc.query(
				`
					WITH mine AS (SELECT id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
						FROM messages
						WHERE messages.author = ?
						ORDER BY sequence DESC
						LIMIT 20)
					SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
						FROM mine
						JOIN messages_refs ON mine.id = messages_refs.ref
						JOIN messages ON messages_refs.message = messages.id
					UNION
					SELECT * FROM mine
				`,
				[this.hash.substring(1)]
			);
			return r;
		} else if (this.hash.startsWith('#%')) {
			return await tfrpc.rpc.query(
				`
					SELECT id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
					FROM messages
					WHERE id = ?1
					UNION
					SELECT id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
					FROM messages JOIN messages_refs
					ON messages.id = messages_refs.message
					WHERE messages_refs.ref = ?1
				`,
				[this.hash.substring(1)]
			);
		} else {
			let promises = [];
			const k_following_limit = 256;
			for (let i = 0; i < this.following.length; i += k_following_limit) {
				promises.push(
					tfrpc.rpc.query(
						`
						WITH news AS (SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
						FROM messages
						JOIN json_each(?) AS following ON messages.author = following.value
						WHERE messages.timestamp > ? AND messages.timestamp < ?
						ORDER BY messages.timestamp DESC)
						SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
							FROM news
							JOIN messages_refs ON news.id = messages_refs.ref
							JOIN messages ON messages_refs.message = messages.id
						UNION
						SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
							FROM news
							JOIN messages_refs ON news.id = messages_refs.message
							JOIN messages ON messages_refs.ref = messages.id
						UNION
						SELECT news.* FROM news
					`,
						[
							JSON.stringify(this.following.slice(i, i + k_following_limit)),
							this.start_time,
							/*
							 ** Don't show messages more than a day into the future to prevent
							 ** messages with far-future timestamps from staying at the top forever.
							 */
							new Date().valueOf() + 24 * 60 * 60 * 1000,
						]
					)
				);
			}
			return [].concat(...(await Promise.all(promises)));
		}
	}

	async load_more() {
		let last_start_time = this.start_time;
		this.start_time = last_start_time - 24 * 60 * 60 * 1000;
		let more = await tfrpc.rpc.query(
			`
				WITH news AS (SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
				FROM messages
				JOIN json_each(?) AS following ON messages.author = following.value
				WHERE messages.timestamp > ?
				AND messages.timestamp <= ?
				ORDER BY messages.timestamp DESC)
				SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
					FROM news
					JOIN messages_refs ON news.id = messages_refs.ref
					JOIN messages ON messages_refs.message = messages.id
				UNION
				SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
					FROM news
					JOIN messages_refs ON news.id = messages_refs.message
					JOIN messages ON messages_refs.ref = messages.id
				UNION
				SELECT news.* FROM news
			`,
			[JSON.stringify(this.following), this.start_time, last_start_time]
		);
		this.messages = await this.decrypt([...more, ...this.messages]);
	}

	async decrypt(messages) {
		console.log('decrypt');
		let result = [];
		for (let message of messages) {
			let content;
			try {
				content = JSON.parse(message?.content);
			} catch {}
			if (typeof content === 'string') {
				let decrypted;
				try {
					decrypted = await tfrpc.rpc.try_decrypt(this.whoami, content);
				} catch {}
				if (decrypted) {
					try {
						message.decrypted = JSON.parse(decrypted);
					} catch {
						message.decrypted = decrypted;
					}
				}
			}
			result.push(message);
		}
		return result;
	}

	async add_messages(messages) {
		this.messages = await this.decrypt([...messages, ...this.messages]);
	}

	render() {
		if (
			!this.messages ||
			this._messages_hash !== this.hash ||
			this._messages_following !== this.following
		) {
			console.log(
				`loading messages for ${this.whoami} (following ${this.following.length})`
			);
			let self = this;
			this.messages = [];
			this._messages_hash = this.hash;
			this._messages_following = this.following;
			this.fetch_messages()
				.then(this.decrypt.bind(this))
				.then(function (messages) {
					self.messages = messages;
					console.log(`loading mesages done for ${self.whoami}`);
				})
				.catch(function (error) {
					alert(JSON.stringify(error, null, 2));
				});
		}
		let more;
		if (!this.hash.startsWith('#@') && !this.hash.startsWith('#%')) {
			more = html`
				<p>
					<button class="w3-button w3-theme-d1" @click=${this.load_more}>
						Load More
					</button>
				</p>
			`;
		}
		return html`
			<tf-news
				id="news"
				whoami=${this.whoami}
				.users=${this.users}
				.messages=${this.messages}
				.following=${this.following}
				.drafts=${this.drafts}
				.expanded=${this.expanded}
			></tf-news>
			${more}
		`;
	}
}

customElements.define('tf-tab-news-feed', TfTabNewsFeedElement);