import { MarkdownView, Plugin, parseYaml, Menu, Editor, View, Notice, MarkdownPostProcessorContext } from 'obsidian';

import Renderer from './chartRenderer';
import { ChartPluginSettings, DEFAULT_SETTINGS } from './constants/settingsConstants';
import { ChartSettingTab } from './ui/settingsTab';
import { CreationHelperModal } from './ui/creationHelperModal';
import { addIcons } from 'src/ui/icons';
import { chartFromTable } from 'src/chartFromTable';
import { base64ToArrayBuffer, renderError, saveImageToVaultAndPaste } from 'src/util';

export default class ChartPlugin extends Plugin {

	settings: ChartPluginSettings;
	renderer: Renderer;

	postprocessor = async (content: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {

		let data;
		try {
			data = await parseYaml(content.replace(/	/g, '    '));
		} catch (error) {
			renderError(error, el);
			return;
		}

		if(!data.id) {
			if (!data || !data.type || !data.labels || !data.series) {
				renderError("Missing type, labels or series", el)
				return;
			}
		}

		await this.renderer.renderFromYaml(data, el, ctx);
	}

	async loadSettings() {
		this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
	}

	async saveSettings() {
		await this.saveData(this.settings);
	}

	async onload() {
		console.log('loading plugin: Obsidian Charts');

		await this.loadSettings()

		addIcons();

		this.renderer = new Renderer(this);

		//@ts-ignore
		window.renderChart = this.renderer.renderRaw;

		this.addSettingTab(new ChartSettingTab(this.app, this));

		this.addCommand({
			id: 'creation-helper',
			name: 'Insert new Chart',
			checkCallback: (checking: boolean) => {
				let leaf = this.app.workspace.activeLeaf;
				if (leaf.view instanceof MarkdownView) {
					if (!checking) {
						new CreationHelperModal(this.app, leaf.view, this.settings, this.renderer).open();
					}
					return true;
				}
				return false;
			}
		});

		this.addCommand({
			id: 'chart-from-table-column',
			name: 'Create Chart from Table (Column oriented Layout)',
			editorCheckCallback: (checking: boolean, editor: Editor, view: View) => {
				let selection = editor.getSelection();
				if (view instanceof MarkdownView && selection.split('\n').length >= 3 && selection.split('|').length >= 2) {
					if (!checking) {
						chartFromTable(editor, 'columns');
					}
					return true;
				}
				return false;
			}
		});

		this.addCommand({
			id: 'chart-from-table-row',
			name: 'Create Chart from Table (Row oriented Layout)',
			editorCheckCallback: (checking: boolean, editor: Editor, view: View) => {
				if (view instanceof MarkdownView && editor.getSelection().split('\n').length >= 3 && editor.getSelection().split('|').length >= 2) {
					if (!checking) {
						chartFromTable(editor, 'rows');
					}
					return true;
				}
				return false;
			}
		});

		this.addCommand({
			id: 'chart-to-svg',
			name: 'Create Image from Chart',
			editorCheckCallback: (checking: boolean, editor: Editor, view: View) => {
				if (view instanceof MarkdownView && editor.getSelection().startsWith("```chart") && editor.getSelection().endsWith("```")) {
					if (!checking) {
						new Notice("Rendering Chart...")
						saveImageToVaultAndPaste(editor, this.app, this.renderer, view.file, this.settings);
					}
					return true;
				}
				return false;
			}
		});

		this.registerMarkdownCodeBlockProcessor('chart', this.postprocessor);
		this.registerMarkdownCodeBlockProcessor('advanced-chart', async (data, el) => this.renderer.renderRaw(await JSON.parse(data), el));

		// Remove this ignore when the obsidian package is updated on npm
		// Editor mode
		// @ts-ignore
		this.registerEvent(this.app.workspace.on('editor-menu',
			(menu: Menu, _: Editor, view: MarkdownView) => {
				if (view && this.settings.contextMenu) {
					menu.addItem((item) => {
						item.setTitle("Insert Chart")
							.setIcon("chart")
							.onClick((_) => {
								new CreationHelperModal(this.app, view, this.settings, this.renderer).open();
							});
					});
				}
			}));
	}

	onunload() {
		console.log('unloading plugin: Obsidian Charts');
	}

}