import { MarkdownView, Plugin } from "obsidian";
// import { drawSelection } from "@codemirror/view";
import { PreviewExtendedSyntax } from "src/preview-mode/post-processor";
import { ColorConfig, PluginSettings } from "src/types";
import { DEFAULT_SETTINGS } from "src/settings";
import { ExtendedSettingTab } from "src/settings/interface";
import { pluginFacet, settingsFacet } from "src/editor-mode/facets";
import { configureDelimLookup, deepCopy, reconfigureDelimLookup } from "src/utils";
import { appFacet } from "src/editor-mode/facets";
import { editorExtendedSyntax } from "src/editor-mode/extensions";
import { refresherAnnot } from "src/editor-mode/annotations";
import { StyleSheetHandler } from "src/stylesheet-handler";
import { createColorConfig, createCSSRuleFromColorConfig, getDefaultColorConfigs } from "src/color-management";
import { Theme } from "src/enums";

export default class ExtendedMarkdownSyntax extends Plugin {
    settings: PluginSettings;
    colorsHandler: StyleSheetHandler;
    opacityHandler: StyleSheetHandler;
    async onload() {
        await this.loadSettings();
        this.addSettingTab(new ExtendedSettingTab(this.app, this));
        configureDelimLookup(this.settings);
        this.registerEditorExtension([
            appFacet.of(this.app),
            pluginFacet.of(this),
            settingsFacet.of(this.settings),
            editorExtendedSyntax
        ]);
        this.registerMarkdownPostProcessor(new PreviewExtendedSyntax(this.settings).postProcess);
        this.colorsHandler = new StyleSheetHandler(this);
        this.opacityHandler = new StyleSheetHandler(this);
        this.buildColorsStyleSheet();
        this.opacityHandler.insert(`body.theme-light{--hl-opacity:${this.settings.lightModeHlOpacity}}`);
        this.opacityHandler.insert(`body.theme-dark{--hl-opacity:${this.settings.darkModeHlOpacity}}`);
        console.log("Load Extended Markdown Syntax");
    }
    async loadSettings() {
        this.settings = Object.assign({}, deepCopy(DEFAULT_SETTINGS), await this.loadData());
    }
    async saveSettings() {
        await this.saveData(this.settings);
    }
    onunload(): void {
        this.colorsHandler.destroy();
        this.opacityHandler.destroy();
        console.log("Unload Extended Markdown Syntax");
    }
    reconfigureDelimLookup() {
        reconfigureDelimLookup(this.settings);
    }
    /** Get the settings change effect without reload the whole app. */
    refreshMarkdownView() {
        this.app.workspace.iterateAllLeaves(leaf => {
            let view = leaf.view;
            if (view instanceof MarkdownView) {
                let cmView = view.editor.cm;
                cmView.dispatch({
                    annotations: refresherAnnot.of(true),
                });
                view.previewMode.rerender(true);
            }
        });
    }
    buildColorsStyleSheet(callback?: (colorConfig: ColorConfig, colorConfigs: ColorConfig[]) => unknown) {
        let colorConfigs = this.settings.colorConfigs;
        for (let i = 0; i < colorConfigs.length; i++) {
            let ruleStr = createCSSRuleFromColorConfig(colorConfigs[i]);
            this.colorsHandler.insert(ruleStr);
            if (callback) { callback(colorConfigs[i], colorConfigs) }
        }
    }
    setHlOpacity(value: number, theme: Theme) {
        let selector = theme == Theme.LIGHT
                ? "body.theme-light"
                : "body.theme-dark",
            property = "--hl-opacity",
            // The index of light mode opacity is 0, and dark mode opacity is 1.
            ruleIndex = theme;
        this.opacityHandler.replace(`${selector}{${property}:${value}}`, ruleIndex);
    }
    rebuildColorsStyleSheet(callback?: (colorConfig: ColorConfig, colorConfigs: ColorConfig[]) => unknown) {
        this.colorsHandler.removeAll();
        this.buildColorsStyleSheet(callback);
    }
    addNewColor() {
        let index = this.settings.colorConfigs.length,
            newConfig = createColorConfig("color-" + index, "#ffd000", "Color " + index),
            ruleStr = createCSSRuleFromColorConfig(newConfig);
        this.settings.colorConfigs.push(newConfig);
        this.colorsHandler.insert(ruleStr, index);
    }
    revertColorConfigs(callback?: (colorConfig: ColorConfig, colorConfigs: ColorConfig[]) => unknown) {
        let configs = this.settings.colorConfigs;
        configs.splice(0, configs.length, ...getDefaultColorConfigs());
        this.rebuildColorsStyleSheet(callback);
    }
}