import { CustomHTMLElement } from "./lib/custom_html_element.mjs";
import { API } from 'api'

export class N2File extends CustomHTMLElement {
	static {// {{{
		this.tmpl = document.createElement('template')
		this.tmpl.innerHTML = `
			<style>
				:host {
					display: inline-grid;
					grid-template-columns: min-content min-content;
					align-items: end;
					white-space: nowrap;
					cursor: pointer;

					.el-image {
						max-width: var(--thumbnail-width);
						max-height: var(--thumbnail-height);
					}

					.el-filename {
						display: none;
						font-weight: bold;
						background-color: #ddd;
						border-radius: 4px;
						padding: 4px 8px;
						margin-left: 8px;
					}
				}
			</style>
			<img data-el="image" src="/images/${_VERSION}/file_icons/generic.svg">
			<div data-el="filename"></div>
		`
	}// }}}
	constructor() {// {{{
		super(true)

		this.streamLocalFile = false
		this.uuid = null

		this.addEventListener('click', event => {
			event.preventDefault()
			event.stopPropagation()

			// Download to disk.
			if (event.shiftKey) {
				this.downloadToDisk()
				return
			}

			// Open in browser.
			this.openInBrowser(event)
		})

		this.render()
	}// }}}
	openInBrowser(event) {// {{{
		if (this.streamLocalFile)
			window.open(
				`/stream-local?uuid=${this.metadata.UUID}`,
				event.ctrlKey ? '_blank' : '_self',
			)
		else {
			const jwt = localStorage.getItem('token')
			window.open(
				`/file/uuid/${this.uuid}?jwt=${jwt}`,
				event.ctrlKey ? '_blank' : '_self',
			)
		}
	}// }}}
	async downloadToDisk() {// {{{
		try {
			// TODO: implement download of remote content.
			if (this.streamLocalFile === false)
				throw new Error('This file is only available online. Download not implemented yet.')

			const handle = await window.showSaveFilePicker({
				suggestedName: this.metadata.name,
			})

			const writable = await handle.createWritable()
			const blobStream = await globalThis.nodeStore.fileSegments.getStream(this.uuid)
			await blobStream.pipeTo(writable)
		} catch (err) {
			if (err.name == 'AbortError')
				return
			console.error(err)
			alert(err.message)
		}
	}// }}}
	async render() {// {{{
		const src = this.getAttribute('src')

		// N2's db:// URLs are fetched from IndexedDB.
		if (src.toLowerCase().match('^db://[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')) {
			// image population has to happen asynchronously,
			// while Marked lib has to be returned a string when exiting this function.
			// populateImg makes sure this returned img element exists and then populates it
			// with the image from IndexedDB.
			const fileUUID = src.slice(5)

			this.uuid = fileUUID
			const md = await globalThis.nodeStore.filesMetadata.get(fileUUID)

			if (md) {
				this.metadata = md
				this.streamLocalFile = true
				this.renderLocalFile(md)
			} else {
				/* <file> can be undefined when a node is retrieved but files aren't synced.
				 * Try to show from server.
				 *
				 * Metadata is needed to know whether to display an image or the file representation. */
				try {
					const res = await API.query('GET', `/file/uuid/${fileUUID}/metadata`)
					this.renderRemoteFile(res.Metadata)
				} catch (err) {
					console.error(err)
				}
			}

		} else
			// Probably an external URL.
			this.elImage.src = src
	}// }}}
	async renderLocalFile(fileMetadata) {// {{{
		if (fileMetadata.type.startsWith('image/'))
			this.elImage.src = `/stream-local?uuid=${fileMetadata.UUID}`
		else {
			// Check for and use an existing MIME type icon.
			// Place them in static/images/file_icons/ and replace the slash with an underscore.
			const url = `/images/${_VERSION}/file_icons/${fileMetadata.type.replaceAll('/', '_')}.svg`
			const res = await fetch(url)
			if (res.ok)
				this.elImage.src = url

			this.elFilename.innerText = fileMetadata.name
			this.elFilename.style.display = 'block'
		}
	}// }}}
	async renderRemoteFile(md) {// {{{
		if (md.Type.startsWith('image/')) {
			const jwt = localStorage.getItem('token')
			this.elImage.src = `/file/uuid/${md.UUID}?jwt=${jwt}`
		} else {
			// Check for and use an existing MIME type icon.
			// Place them in static/images/file_icons/ and replace the slash with an underscore.
			const url = `/images/${_VERSION}/file_icons/${md.Type.replaceAll('/', '_')}.svg`
			const res = await fetch(url)
			if (res.ok)
				this.elImage.src = url

			this.elFilename.innerText = md.Name
			this.elFilename.style.display = 'block'
		}
	}// }}}
}
customElements.define('n2-file', N2File)
