// Keyboard shortcuts
chrome.commands.onCommand.addListener(async function (command) {
    if (command == "saveSelection") {
        await saveSelection();
    } else if (command == "saveWholePage") {
        await saveWholePage();
    } else if (command == "saveTabs") {
        await saveTabs();
    } else if (command == "saveCroppedScreenshot") {
        const activeTab = await getActiveTab();
        await saveCroppedScreenshot(activeTab.url);
    } else {
        console.log("Unrecognized command", command);
    }
});
function cropImage(newArea, dataUrl) {
	return new Promise((resolve, reject) => {
		const img = new Image();
		img.onload = function () {
			const canvas = document.createElement('canvas');
			canvas.width = newArea.width;
			canvas.height = newArea.height;
			const ctx = canvas.getContext('2d');
			ctx.drawImage(img, newArea.x, newArea.y, newArea.width, newArea.height, 0, 0, newArea.width, newArea.height);
			resolve(canvas.toDataURL());
		};
		img.src = dataUrl;
	});
}
async function takeCroppedScreenshot(cropRect) {
	const activeTab = await getActiveTab();
	const zoom = await browser.tabs.getZoom(activeTab.id) *  window.devicePixelRatio;
	const newArea = Object.assign({}, cropRect);
	newArea.x *= zoom;
	newArea.y *= zoom;
	newArea.width *= zoom;
	newArea.height *= zoom;
	const dataUrl = await browser.tabs.captureVisibleTab(null, { format: 'png' });
	return await cropImage(newArea, dataUrl);
}
async function takeWholeScreenshot() {
	// this saves only visible portion of the page
	// workaround to save the whole page is to scroll & stitch
	// example in https://github.com/mrcoles/full-page-screen-capture-chrome-extension
	// see page.js and popup.js
	return await browser.tabs.captureVisibleTab(null, { format: 'png' });
}
browser.runtime.onInstalled.addListener(() => {
	if (isDevEnv()) {
		browser.browserAction.setIcon({
			path: 'icons/32-dev.png',
		});
	}
});
browser.contextMenus.create({
	id: "trilium-save-selection",
	title: "Save selection to Trilium",
	contexts: ["selection"]
});
browser.contextMenus.create({
	id: "trilium-save-cropped-screenshot",
	title: "Clip screenshot to Trilium",
	contexts: ["page"]
});
browser.contextMenus.create({
	id: "trilium-save-cropped-screenshot",
	title: "Crop screen shot to Trilium",
	contexts: ["page"]
});
browser.contextMenus.create({
	id: "trilium-save-whole-screenshot",
	title: "Save whole screen shot to Trilium",
	contexts: ["page"]
});
browser.contextMenus.create({
	id: "trilium-save-page",
	title: "Save whole page to Trilium",
	contexts: ["page"]
});
browser.contextMenus.create({
	id: "trilium-save-link",
	title: "Save link to Trilium",
	contexts: ["link"]
});
browser.contextMenus.create({
	id: "trilium-save-image",
	title: "Save image to Trilium",
	contexts: ["image"]
});
async function getActiveTab() {
	const tabs = await browser.tabs.query({
		active: true,
		currentWindow: true
	});
	return tabs[0];
}
async function getWindowTabs() {
	const tabs = await browser.tabs.query({
		currentWindow: true
	});
	return tabs;
}
async function sendMessageToActiveTab(message) {
	const activeTab = await getActiveTab();
	if (!activeTab) {
		throw new Error("No active tab.");
	}
	try {
		return await browser.tabs.sendMessage(activeTab.id, message);
	}
	catch (e) {
		throw e;
	}
}
function toast(message, noteId = null, tabIds = null) {
	sendMessageToActiveTab({
		name: 'toast',
		message: message,
		noteId: noteId,
		tabIds: tabIds
	});
}
function blob2base64(blob) {
	return new Promise(resolve => {
		const reader = new FileReader();
		reader.onloadend = function() {
			resolve(reader.result);
		};
		reader.readAsDataURL(blob);
	});
}
async function fetchImage(url) {
	const resp = await fetch(url);
	const blob = await resp.blob();
	return await blob2base64(blob);
}
async function postProcessImage(image) {
	if (image.src.startsWith("data:image/")) {
		image.dataUrl = image.src;
		image.src = "inline." + image.src.substr(11, 3); // this should extract file type - png/jpg
	}
	else {
		try {
			image.dataUrl = await fetchImage(image.src, image);
		}
		catch (e) {
			console.log(`Cannot fetch image from ${image.src}`);
		}
	}
}
async function postProcessImages(resp) {
	if (resp.images) {
		for (const image of resp.images) {
			await postProcessImage(image);
		}
	}
}
async function saveSelection() {
	const payload = await sendMessageToActiveTab({name: 'trilium-save-selection'});
	await postProcessImages(payload);
	const resp = await triliumServerFacade.callService('POST', 'clippings', payload);
	if (!resp) {
		return;
	}
	toast("Selection has been saved to Trilium.", resp.noteId);
}
async function getImagePayloadFromSrc(src, pageUrl) {
	const image = {
		imageId: randomString(20),
		src: src
	};
	await postProcessImage(image);
	const activeTab = await getActiveTab();
	return {
		title: activeTab.title,
		content: ``,
		images: [image],
		pageUrl: pageUrl
	};
}
async function saveCroppedScreenshot(pageUrl) {
	const cropRect = await sendMessageToActiveTab({name: 'trilium-get-rectangle-for-screenshot'});
	const src = await takeCroppedScreenshot(cropRect);
	const payload = await getImagePayloadFromSrc(src, pageUrl);
	const resp = await triliumServerFacade.callService("POST", "clippings", payload);
	if (!resp) {
		return;
	}
	toast("Screenshot has been saved to Trilium.", resp.noteId);
}
async function saveWholeScreenshot(pageUrl) {
	const src = await takeWholeScreenshot();
	const payload = await getImagePayloadFromSrc(src, pageUrl);
	const resp = await triliumServerFacade.callService("POST", "clippings", payload);
	if (!resp) {
		return;
	}
	toast("Screenshot has been saved to Trilium.", resp.noteId);
}
async function saveImage(srcUrl, pageUrl) {
	const payload = await getImagePayloadFromSrc(srcUrl, pageUrl);
	const resp = await triliumServerFacade.callService("POST", "clippings", payload);
	if (!resp) {
		return;
	}
	toast("Image has been saved to Trilium.", resp.noteId);
}
async function saveWholePage() {
	const payload = await sendMessageToActiveTab({name: 'trilium-save-page'});
	await postProcessImages(payload);
	const resp = await triliumServerFacade.callService('POST', 'notes', payload);
	if (!resp) {
		return;
	}
	toast("Page has been saved to Trilium.", resp.noteId);
}
async function saveLinkWithNote(title, content) {
	const activeTab = await getActiveTab();
	if (!title.trim()) {
		title = activeTab.title;
	}
	const resp = await triliumServerFacade.callService('POST', 'notes', {
		title: title,
		content: content,
		clipType: 'note',
		pageUrl: activeTab.url
	});
	if (!resp) {
		return false;
	}
	toast("Link with note has been saved to Trilium.", resp.noteId);
	return true;
}
async function getTabsPayload(tabs) {
	let content = '