import {JupyterFrontEnd, JupyterFrontEndPlugin,ILabShell} from '@jupyterlab/application';
import {NotebookPanel} from '@jupyterlab/notebook';
import { IThemeManager } from '@jupyterlab/apputils';
import {IEditorLanguageRegistry} from '@jupyterlab/codemirror';
import {getVadalogLanguage, MIME, NAME, FILE_EXTENSIONS} from './mode';
import {VadalogButtons} from "./vadalog-buttons";
import { LabIcon, jupyterFaviconIcon, jupyterIcon, jupyterlabWordmarkIcon } from '@jupyterlab/ui-components';
import { Widget } from '@lumino/widgets';


import '../style/index.css';
import {NOTEBOOK_VERSION} from "./constants";
import {VadalogLinter} from "./vadalog-linter";
import {PartialJSONObject} from "@lumino/coreutils";


const plugin: JupyterFrontEndPlugin<void> = {
    id: '@g2nb/jupyterlab-theme:plugin',
    requires: [IThemeManager, ILabShell],
    activate: (app: JupyterFrontEnd, manager: IThemeManager, shell: ILabShell) => {
        const style = '@g2nb/jupyterlab-theme/index.css';

        // Create the g2nb logo
        const g2nb_svg = '<svg height="180px" viewBox="0 0 217 217" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Group-4" transform="translate(0.686292, 0.979185)" fill="#000000" stroke="#000000" stroke-width="15"> <circle id="Oval" transform="translate(108.310219, 161.599156) rotate(90.000000) translate(-108.310219, -161.599156) " cx="108.310219" cy="161.599156" r="14.435824"></circle> <circle id="Oval" transform="translate(160.721723, 107.432786) rotate(90.000000) translate(-160.721723, -107.432786) " cx="160.721723" cy="107.432786" r="14.435824"></circle> <circle id="Oval" transform="translate(193.186743, 139.897806) rotate(90.000000) translate(-193.186743, -139.897806) " cx="193.186743" cy="139.897806" r="14.435824"></circle> <circle id="Oval" transform="translate(140.775239, 194.064176) rotate(90.000000) translate(-140.775239, -194.064176) " cx="140.775239" cy="194.064176" r="14.435824"></circle> <circle id="Oval" transform="translate(75.224761, 21.935824) rotate(90.000000) translate(-75.224761, -21.935824) " cx="75.224761" cy="21.935824" r="14.435824"></circle> <circle id="Oval" transform="translate(21.935824, 75.224761) rotate(90.000000) translate(-21.935824, -75.224761) " cx="21.935824" cy="75.224761" r="14.435824"></circle> <circle id="Oval" transform="translate(54.400844, 106.812348) rotate(90.000000) translate(-54.400844, -106.812348) " cx="54.4008436" cy="106.812348" r="14.435824"></circle> <circle id="Oval" transform="translate(108.673664, 56.519154) rotate(-45.000000) translate(-108.673664, -56.519154) " cx="108.673664" cy="56.5191542" r="14.435824"></circle> <circle id="Oval" cx="139.897806" cy="22.813257" r="14.435824"></circle> <circle id="Oval" cx="194.064176" cy="75.224761" r="14.435824"></circle> <circle id="Oval" cx="21.935824" cy="140.775239" r="14.435824"></circle> <circle id="Oval" cx="75.224761" cy="194.064176" r="14.435824"></circle> </g> </g> </svg>       ';
        const g2nb_icon = new LabIcon({ name: 'ui-components:g2nb', svgstr: g2nb_svg });

        // Attach the g2nb logo in the top left
        const logo = new Widget();
        g2nb_icon.element({
            container: logo.node,
            elementPosition: 'center',
            margin: '2px 2px 2px 8px',
            height: 'auto',
            width: '16px'
        });
        logo.id = 'jp-g2nbLogo';
        shell.add(logo, 'top', { rank: 0 });

        // Set the icons elsewhere
        jupyterFaviconIcon.svgstr = g2nb_svg;
        jupyterIcon.svgstr = g2nb_svg;
        jupyterlabWordmarkIcon.svgstr = g2nb_svg;

        // Register the plugin
        manager.register({
            name: 'g2nb',
            isLight: true,
            themeScrollbars: true,
            load: () => manager.loadCSS(style),
            unload: () => Promise.resolve(undefined)
        });
    },
    autoStart: true
};


/**
 * The extension for displaying the custom buttons of the Vadalog engine with the logic for displaying explain windows
 */
const buttonExtension: JupyterFrontEndPlugin<void> = {
    id: 'vadalog:buttons',
    autoStart: true,
    requires: [],
    activate: (app: JupyterFrontEnd) => {
        // Vadalog Extension Loaded in Dev Mode
        app.docRegistry.addWidgetExtension('Notebook', new VadalogButtons());
    }
};

/**
 *  The extension for Vadalog support with Codemirror in the code editor
 *  maybe consider this extension in future development: https://github.com/krassowski/jupyterlab-lsp
 *  A similar extension can be found here: https://github.com/ibqn/jupyterlab-codecellbtn/blob/master/src/index.tsx
 *  also see these jupyterlab issues: https://github.com/jupyterlab/jupyterlab/issues/1670, https://github.com/jupyterlab/jupyterlab/issues/1278
 */
const editorExtension: JupyterFrontEndPlugin<void> = {
    id: 'vadalog:editor',
    autoStart: true,
    requires: [IEditorLanguageRegistry],
    activate: (app: JupyterFrontEnd, languages: IEditorLanguageRegistry) => {
        // Register Vadalog language with JupyterLab
        languages.addLanguage({
            name: NAME,
            displayName: 'Vadalog',
            mime: MIME,
            extensions: FILE_EXTENSIONS,
            support: getVadalogLanguage()
        });
        
        app.docRegistry.addWidgetExtension('Notebook', new VadalogLinter());
    }
};

/**
 * An extension that introduces versioning of Vadalog JupyterLab notebooks by setting the version in the metadata.
 * Listens for the "notebook:create-new" command in the JupyterLab framework, which creates a new notebook.
 * Sets the vadalog metadata for "version" as the global constant and "programParameters" as an empty list.
 */
const notebookVersioning: JupyterFrontEndPlugin<void> = {
    id: 'vadalog:versioning',
    autoStart: true,
    requires: [],
    activate: (app: JupyterFrontEnd) => {

        // listen for the command executed when a new notebook is created
        app.commands.commandExecuted.connect((registry, args) => {
            if (args.id == "notebook:create-new") {
                args.result.then((widget: NotebookPanel) => {

                    // set the vadalog values for metadata in the new notebook
                    widget.context.ready.then(() => {
                        const metadata: any = widget.content.model!.metadata;
                        const vadalogMetadata: PartialJSONObject = {
                            "programParameters": [],
                            "version": NOTEBOOK_VERSION
                        };
                        metadata.set("vadalog", vadalogMetadata);
                    });
                });
            }
        });
    }
};

/**
 * Export the extensions as default.
 */
const plugins: JupyterFrontEndPlugin<any>[] = [
    buttonExtension,
    editorExtension,
    notebookVersioning,
    plugin
];

export default plugins;
