import { Api } from './Api';
import { Mention } from './Mention';
import { c } from './lib/Log';
import { Utils } from './lib/Utils';
import { VanillaTilt } from './vanilla-tilt';
import { ShareScreenshotModal, SavePublishModal } from './modals';

/// We experimented with a couple of different build systems
/// to integrate Quill (for instance module-then-postprocessing
/// like in `web3d`) but none worked really well so we just
/// hotlink the js and basically copy/paste the @types/quill
/// declaration here.
/// Update: we now use rollup (for html2canvas), but quill is
/// still a pain so it's still not in the same bundle.

const DEBUG = false;
/// ^^ when debugging the quill integration, add the quill.snow.css to layout.hbs
/// <link href="/front/node_modules/quill/dist/quill.snow.css" rel="stylesheet">
/// <link href="/front/node_modules/quill/dist/quill.core.css" rel="stylesheet">
/// We tried doing it programmatically here but it's a bit slow.
if (DEBUG) {
	document.head.insertAdjacentHTML(
		'beforeend', 
		`<link href="/front/node_modules/quill/dist/quill.snow.css" rel="stylesheet">`
	);
	/// ^^ add css to debug. Do it as early as possible.
}

enum Page {
	app, landing, model
}
const App = {
	page:
		  (document.body.classList.contains('app'))     ? Page.app
		: (document.body.classList.contains('landing')) ? Page.landing
		: Page.model
	,
	editable:           document.body.dataset.editable === 'true',
	header: {
		shuffleBtn:     document.querySelector('header .js-shuffle')  as HTMLAnchorElement,
		triggerBtn:     document.querySelector('header .js-trigger')  as HTMLAnchorElement,
		mainInfoBtn:    document.querySelector('header .title .info') as HTMLImageElement,
		shareBtn:       document.querySelector<HTMLAnchorElement>('header .js-share'),
		saveBtn:        document.querySelector<HTMLAnchorElement>('header .js-save'),
		duplicateBtn:   document.querySelector<HTMLAnchorElement>('header .js-duplicate'),
	},
	shareScreenBtn:     document.querySelector('.page-container .js-share')  as HTMLAnchorElement,
	loaderEditor:       document.querySelector('.page-container .js-loader') as HTMLImageElement,
	sliders:      Array.from(
		document.querySelectorAll('.decoder-settings input.slider')
	) as HTMLInputElement[],
	INITIAL_CONTENT: {} as Delta,
	/**
	 * Helper function to more cleanly route different page types.
	 */
	onLoad: (p: Page, callback: () => void) => {
		if (p === App.page) {
			document.addEventListener('DOMContentLoaded', () => {
				callback();
			});
		}
	},
};

const PROMPTS = [
	`Before boarding your rocket to Mars, remember to pack these items`,
	`In a shocking finding, scientist discovered a herd of unicorns living in a remote, previously unexplored valley, in the Andes Mountains. Even more surprising to the researchers was the fact that the unicorns spoke perfect English.`,
	`Legolas and Gimli advanced on the orcs, raising their weapons with a harrowing war cry.`,
	`Today, scientists confirmed the worst possible outcome: the massive asteroid will collide with Earth`,
	`
		Thor: The Tesseract belongs on Asgard, no human is a match for it.
		Tony turns to leave, but Steve stops him.
		Steve: You're not going alone!
		Tony: You gonna stop me?
	`.replace(/\t/g, "").trim().concat("\n"),
];




App.onLoad(Page.app, () => {
	const modalScreenshot = new ShareScreenshotModal;
	
	const opts: QuillOptionsStatic = DEBUG
		? {
			theme: 'snow',
			modules: {
				mention: {},
			},
		}
		: {
			theme: undefined,
			// formats: [],
			modules: {
				toolbar: [],
				mention: {},
			},
		}
	;
	if (! App.editable) {
		opts.readOnly = true;
	}
	const quill = new Quill('div.editor', opts);
	const mention = quill.getModule('mention') as Mention;
	(<any>window).quill = quill;
	const QUILL_C = (<any>window).QUILL_C;
	if (QUILL_C) {
		quill.setContents(QUILL_C);
	}
	
	
	
	quill.container.appendChild(App.loaderEditor);
	quill.container.appendChild(App.shareScreenBtn);
	
	//
	//       div.editor .ql-container          <-- quill.container
	//     +--------------------------------+
	//     | div.ql-editor contenteditable  |  <-- quill.root
	//     | +----------------------------+ |
	//     | |                            | |
	//     | |                            | |
	//     | +----------------------------+ |
	//     +--------------------------------+
	//
	
	quill.keyboard.addBinding({ key: Mention.Keys.TAB }, () => {
		triggerAutocomplete();
	});
	quill.keyboard.bindings[Mention.Keys.TAB].unshift(
		quill.keyboard.bindings[Mention.Keys.TAB].pop()
	);
	/// ^^ important.
	/// ^^ place it at beginning of bindings.
	
	
	const triggerAutocomplete = async () => {
		/// vv position loader
		mention.setCursorPos();
		const cursorBbox = quill.getBounds(mention.getCursorPos());
		App.loaderEditor.style.top  = `${cursorBbox.top - 4}px`;
		App.loaderEditor.style.left = `${cursorBbox.left + 4}px`;
		App.loaderEditor.classList.remove('hide');
		
		/// vv Launch api request.
		const text = quill.getText(0, mention.getCursorPos());
		// ^^ That is so much simpler that what we used to do
		// when we were embbedding objects like in `quill-mention`.
		c.debug(
			`%c[About to launch autocomplete for]`,
			`color: green;`,
			text,
		);
		const o = await Api.shared.postWithSettings({ context: text });
		App.loaderEditor.classList.add('hide');
		
		/// vv Trigger mention module.
		for (const x of o.sentences) {
			c.log(x.value);
		}
		mention.trigger(
			o.sentences.map(x => x.value)
		);
	};
	
	
	App.header.duplicateBtn?.addEventListener('click', async (e) => {
		e.preventDefault();
		const url = await Api.shared.postDuplicate();
		window.location.href = url;
	});
	
	
	if (! App.editable) {
		return ;
	}
	/**
	 * vv Below is only in editable mode.
	 */
	
	const modalSave = new SavePublishModal(quill);
	
	App.header.shuffleBtn.addEventListener('click', (e) => {
		e.preventDefault();
		quill.setText(
			Utils.randomItem(PROMPTS)
		);
		quill.setSelection(quill.getLength(), 0);
		/// ^^ github.com/quilljs/quill/issues/2635
		triggerAutocomplete();
	});
	App.header.triggerBtn.addEventListener('click', (e) => {
		e.preventDefault();
		triggerAutocomplete();
	});
	App.header.shareBtn?.addEventListener('click', async (e) => {
		e.preventDefault();
		const text = `Write With Transformer via @huggingface`;
		window.open(`https://twitter.com/share?url=${ encodeURIComponent(window.location.href) }&text=${ encodeURIComponent(text) }`);
	});
	App.header.saveBtn?.addEventListener('click', (e) => {
		e.preventDefault();
		mention.hideMentionList();
		modalSave.show();
	});
	
	App.shareScreenBtn.addEventListener('click', async (e) => {
		e.preventDefault();
		mention.hideMentionList();
		modalScreenshot.show();
	});
	quill.on('text-change', () => {
		App.shareScreenBtn.classList.remove('hide'); /// <- we use a fadeout effect.
		const hasTextFromAI = quill.getContents()
			.ops
			.some(op => op.attributes && op.attributes.bold === true)
		;
		App.shareScreenBtn.classList.toggle('fadeout', ! hasTextFromAI);
	});
	document.addEventListener('click', (e) => {
		/// Handle clicks on links inside the editor.
		if (! (
			   e.target instanceof HTMLAnchorElement
			&& e.target.closest('div.ql-editor') !== null
		)) {
			return ;
		}
		/// Ok, let's do this.
		e.preventDefault();
		e.stopPropagation();
		const href = e.target.getAttribute('href'); /// <- caution, get the original string.
		c.debug(`[click]`, href);
		if (href === '#js-shuffle') {
			App.header.shuffleBtn.click();
		} else {
			window.open(e.target.href);
		}
	});
	document.addEventListener("scroll", e => {
		const trigger = document.getElementsByClassName("js-trigger")[0] as HTMLAnchorElement;
		if (scrollY > 100) {
			trigger.style.position = "fixed";
			trigger.style.top = "10px";
			trigger.style.border = "1px solid blue";
			trigger.style.backgroundColor = "white";
			trigger.style.borderRadius = "100px";
			trigger.style.padding = "5px";
			trigger.style.zIndex = "1";
			trigger.style.left = "50%";
			trigger.style.transform = "translateX(-50%)";
		} else {
			trigger.style.position = "relative";
			trigger.style.top = "auto";
			trigger.style.border = "none";
			trigger.style.backgroundColor = "white";
			trigger.style.borderRadius = "0";
			trigger.style.padding = "0";
			trigger.style.zIndex = "1";
			trigger.style.left = "auto"
		}
	});
	
	/**
	 * Settings
	 */
	const handleSliderChange = (slider: HTMLInputElement) => {
		const div = slider.parentNode as HTMLDivElement;
		const spanVal = div.querySelector('.js-val') as HTMLSpanElement;
		const value = Number.isInteger(slider.valueAsNumber)
			? slider.valueAsNumber
			: Number(slider.valueAsNumber.toFixed(2))
		;
		const valueKey = `value-${value}`;
		if (slider.dataset[valueKey]) {
			spanVal.innerText = slider.dataset[valueKey]!;
		} else {
			spanVal.innerText = value.toString();
		}
		const min = Number(slider.getAttribute('min'));
		const max = Number(slider.getAttribute('max'));
		if (value < min + (max - min) / 3) {
			spanVal.className = "js-val green";
		} else if (value < min + 2 * (max - min) / 3) {
			spanVal.className = "js-val orange";
		} else {
			spanVal.className = "js-val red";
		}
		const isInverted = slider.classList.contains('js-inverted');
		if (isInverted) {
			if (spanVal.classList.contains('green')) {
				spanVal.classList.remove('green');
				spanVal.classList.add('red');
			} else if (spanVal.classList.contains('red')) {
				spanVal.classList.remove('red');
				spanVal.classList.add('green');
			}
		}
	};
	for (const slider of App.sliders) {
		handleSliderChange(slider);
		slider.addEventListener('input', () => {
			handleSliderChange(slider);
		});
	}
});



App.onLoad(Page.landing, () => {
	/**
	 * VanillaTilt
	 */
	VanillaTilt.init(document.querySelectorAll("[data-tilt]"), {
		glare: true,
		scale: 1.06,
		'max-glare': 0.3,
		speed: 400,
	});
});