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

class TfProfileElement extends LitElement {
	static get properties() {
		return {
			editing: {type: Object},
			whoami: {type: String},
			id: {type: String},
			users: {type: Object},
			size: {type: Number},
			server_follows_me: {type: Boolean},
			following: {type: Boolean},
			blocking: {type: Boolean},
		};
	}

	static styles = styles;

	constructor() {
		super();
		let self = this;
		this.editing = null;
		this.whoami = null;
		this.id = null;
		this.users = {};
		this.size = 0;
		this.server_follows_me = undefined;
	}

	async load() {
		if (this.whoami !== this._follow_whoami) {
			this._follow_whoami = this.whoami;
			this.following = undefined;
			this.blocking = undefined;

			let result = await tfrpc.rpc.query(
				`
				SELECT json_extract(content, '$.following') AS following
				FROM messages WHERE author = ? AND
				json_extract(content, '$.type') = 'contact' AND
				json_extract(content, '$.contact') = ? AND
				following IS NOT NULL
				ORDER BY sequence DESC LIMIT 1
			`,
				[this.whoami, this.id]
			);
			this.following = result?.[0]?.following ?? false;
			result = await tfrpc.rpc.query(
				`
				SELECT json_extract(content, '$.blocking') AS blocking
				FROM messages WHERE author = ? AND
				json_extract(content, '$.type') = 'contact' AND
				json_extract(content, '$.contact') = ? AND
				blocking IS NOT NULL
				ORDER BY sequence DESC LIMIT 1
			`,
				[this.whoami, this.id]
			);
			this.blocking = result?.[0]?.blocking ?? false;
		}
	}

	async initial_load() {
		this.server_follows_me = undefined;
		let server_id = await tfrpc.rpc.getServerIdentity();
		let followed = await tfrpc.rpc.query(
			`
			SELECT json_extract(content, '$.following') AS following
			FROM messages
			WHERE author = ? AND
			json_extract(content, '$.type') = 'contact' AND
			json_extract(content, '$.contact') = ? ORDER BY sequence DESC LIMIT 1
		`,
			[server_id, this.whoami]
		);
		let is_followed = false;
		for (let row of followed) {
			is_followed = row.following != 0;
		}
		this.server_follows_me = is_followed;
	}

	modify(change) {
		tfrpc.rpc
			.appendMessage(
				this.whoami,
				Object.assign(
					{
						type: 'contact',
						contact: this.id,
					},
					change
				)
			)
			.catch(function (error) {
				alert(error?.message);
			});
	}

	follow() {
		this.modify({following: true});
	}

	unfollow() {
		this.modify({following: false});
	}

	block() {
		this.modify({blocking: true});
	}

	unblock() {
		this.modify({blocking: false});
	}

	edit() {
		let original = this.users[this.id];
		this.editing = {
			name: original.name,
			description: original.description,
			image: original.image,
			publicWebHosting: original.publicWebHosting,
		};
		console.log(this.editing);
	}

	save_edits() {
		let self = this;
		let message = {
			type: 'about',
			about: this.whoami,
		};
		for (let key of Object.keys(this.editing)) {
			if (this.editing[key] !== this.users[this.id][key]) {
				message[key] = this.editing[key];
			}
		}
		tfrpc.rpc
			.appendMessage(this.whoami, message)
			.then(function () {
				self.editing = null;
			})
			.catch(function (error) {
				alert(error?.message);
			});
	}

	discard_edits() {
		this.editing = null;
	}

	attach_image() {
		let self = this;
		let input = document.createElement('input');
		input.type = 'file';
		input.onchange = function (event) {
			let file = event.target.files[0];
			file
				.arrayBuffer()
				.then(function (buffer) {
					let bin = Array.from(new Uint8Array(buffer));
					return tfrpc.rpc.store_blob(bin);
				})
				.then(function (id) {
					self.editing = Object.assign({}, self.editing, {image: id});
					console.log(self.editing);
				})
				.catch(function (e) {
					alert(e.message);
				});
		};
		input.click();
	}

	async server_follow_me(follow) {
		try {
			await tfrpc.rpc.setServerFollowingMe(this.whoami, follow);
		} catch (e) {
			console.log(e);
		}
		try {
			await this.initial_load();
		} catch (e) {
			console.log(e);
		}
	}

	render() {
		if (
			this.id == this.whoami &&
			this.editing &&
			this.server_follows_me === undefined
		) {
			this.initial_load();
		}
		this.load();
		let self = this;
		let profile = this.users[this.id] || {};
		tfrpc.rpc
			.query(
				`SELECT SUM(LENGTH(content)) AS size FROM messages WHERE author = ?`,
				[this.id]
			)
			.then(function (result) {
				self.size = result[0].size;
			});
		let edit;
		let follow;
		let block;
		if (this.id === this.whoami) {
			if (this.editing) {
				let server_follow;
				if (this.server_follows_me === true) {
					server_follow = html`<button
						class="w3-button w3-theme-d1"
						@click=${() => this.server_follow_me(false)}
					>
						Server, Stop Following Me
					</button>`;
				} else if (this.server_follows_me === false) {
					server_follow = html`<button
						class="w3-button w3-theme-d1"
						@click=${() => this.server_follow_me(true)}
					>
						Server, Follow Me
					</button>`;
				}
				edit = html`
					<button class="w3-button w3-theme-d1" @click=${this.save_edits}>
						Save Profile
					</button>
					<button class="w3-button w3-theme-d1" @click=${this.discard_edits}>
						Discard
					</button>
					${server_follow}
				`;
			} else {
				edit = html`<button class="w3-button w3-theme-d1" @click=${this.edit}>
					Edit Profile
				</button>`;
			}
		}
		if (this.id !== this.whoami && this.following !== undefined) {
			follow = this.following
				? html`<button class="w3-button w3-theme-d1" @click=${this.unfollow}>
						Unfollow
					</button>`
				: html`<button class="w3-button w3-theme-d1" @click=${this.follow}>
						Follow
					</button>`;
		}
		if (this.id !== this.whoami && this.blocking !== undefined) {
			block = this.blocking
				? html`<button class="w3-button w3-theme-d1" @click=${this.unblock}>
						Unblock
					</button>`
				: html`<button class="w3-button w3-theme-d1" @click=${this.block}>
						Block
					</button>`;
		}
		let edit_profile = this.editing
			? html`
			<div style="flex: 1 0 50%; display: flex; flex-direction: column; gap: 8px">
				<div class="w3-container">
					<div>
						<label for="name">Name:</label>
						<input class="w3-input w3-theme-d1" type="text" id="name" value=${this.editing.name} @input=${(event) => (this.editing = Object.assign({}, this.editing, {name: event.srcElement.value}))}></input>
					</div>
					<div><label for="description">Description:</label></div>
					<textarea class="w3-input w3-theme-d1" style="resize: vertical" rows="8" id="description" @input=${(event) => (this.editing = Object.assign({}, this.editing, {description: event.srcElement.value}))}>${this.editing.description}</textarea>
					<div>
						<label for="public_web_hosting">Public Web Hosting:</label>
						<input class="w3-check w3-theme-d1" type="checkbox" id="public_web_hosting" ?checked=${this.editing.publicWebHosting} @input=${(event) => (self.editing = Object.assign({}, self.editing, {publicWebHosting: event.srcElement.checked}))}></input>
					</div>
					<div>
						<button class="w3-button w3-theme-d1" @click=${this.attach_image}>Attach Image</button>
					</div>
				</div>
			</div>`
			: null;
		let image =
			typeof profile.image == 'string' ? profile.image : profile.image?.link;
		image = this.editing?.image ?? image;
		let description = this.editing?.description ?? profile.description;
		return html`<div style="border: 2px solid black; background-color: rgba(255, 255, 255, 0.2); padding: 16px">
			<tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
			<div style="display: flex; flex-direction: row; gap: 1em">
				${edit_profile}
				<div style="flex: 1 0 50%">
					<div><img src=${'/' + image + '/view'} style="width: 256px; height: auto"></img></div>
					<div>${unsafeHTML(tfutils.markdown(description))}</div>
				</div>
			</div>
			<div>
				Following ${profile.following} identities.
				Followed by ${profile.followed} identities.
				Blocking ${profile.blocking} identities.
				Blocked by ${profile.blocked} identities.
			</div>
			<div>
				${edit}
				${follow}
				${block}
			</div>
		</div>`;
	}
}

customElements.define('tf-profile', TfProfileElement);