import { action, computed, observable, ObservableSet, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast } from '../../fields/Doc';
import { ScriptField } from '../../fields/ScriptField';
import { Cast, StrCast } from '../../fields/Types';
import { TraceMobx } from '../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../Utils';
import { Docs, DocUtils } from '../documents/Documents';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { Transform } from '../util/Transform';
import { undoBatch } from '../util/UndoManager';
import { CollectionTreeView } from './collections/CollectionTreeView';
import { DocumentView } from './nodes/DocumentView';
import { DefaultStyleProvider } from './StyleProvider';
import './TemplateMenu.scss';
import React = require('react');

@observer
class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent<HTMLInputElement>, template: string) => void }> {
    render() {
        if (this.props.template) {
            return (
                <li className="templateToggle">
                    <input type="checkbox" checked={this.props.checked} onChange={event => this.props.toggle(event, this.props.template)} />
                    {this.props.template}
                </li>
            );
        } else {
            return null;
        }
    }
}
@observer
class OtherToggle extends React.Component<{ checked: boolean; name: string; toggle: (event: React.ChangeEvent<HTMLInputElement>) => void }> {
    render() {
        return (
            <li className="chromeToggle">
                <input type="checkbox" checked={this.props.checked} onChange={event => this.props.toggle(event)} />
                {this.props.name}
            </li>
        );
    }
}

export interface TemplateMenuProps {
    docViews: DocumentView[];
    templates?: Map<string, boolean>;
}

@observer
export class TemplateMenu extends React.Component<TemplateMenuProps> {
    _addedKeys = new ObservableSet();
    _customRef = React.createRef<HTMLInputElement>();
    @observable private _hidden: boolean = true;

    toggleLayout = (e: React.ChangeEvent<HTMLInputElement>, layout: string): void => {
        this.props.docViews.map(dv => dv.switchViews(e.target.checked, layout, undefined, true));
    };
    toggleDefault = (e: React.ChangeEvent<HTMLInputElement>): void => {
        this.props.docViews.map(dv => dv.switchViews(false, 'layout'));
    };

    @undoBatch
    @action
    toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: string): void => {
        this.props.docViews.forEach(d => (Doc.Layout(d.layoutDoc)['_show' + template] = event.target.checked ? template.toLowerCase() : ''));
    };

    @action
    toggleTemplateActivity = (): void => {
        this._hidden = !this._hidden;
    };

    // todo: add brushes to brushMap to save with a style name
    onCustomKeypress = (e: React.KeyboardEvent) => {
        if (e.key === 'Enter') {
            runInAction(() => this._addedKeys.add(this._customRef.current!.value));
        }
    };
    componentDidMount() {
        !this._addedKeys && (this._addedKeys = new ObservableSet());
        [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))), ...Array.from(Object.keys(this.props.docViews[0].props.Document))]
            .filter(key => key.startsWith('layout_'))
            .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', ''))));
    }

    return100 = () => 300;
    @computed get scriptField() {
        const script = ScriptField.MakeScript('docs.map(d => switchView(d, this))', { this: Doc.name }, { docs: this.props.docViews.map(dv => dv.props.Document) as any });
        return script ? () => script : undefined;
    }
    templateIsUsed = (selDoc: Doc, templateDoc: Doc) => {
        const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
        return StrCast(selDoc.layout_fieldKey) === 'layout_' + template ? 'check' : 'unchecked';
    };
    render() {
        TraceMobx();
        const firstDoc = this.props.docViews[0].props.Document;
        const templateName = StrCast(firstDoc.layout_fieldKey, 'layout').replace('layout_', '');
        const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
        const addedTypes = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
        const templateMenu: Array<JSX.Element> = [];
        this.props.templates?.forEach((checked, template) => templateMenu.push(<TemplateToggle key={template} template={template} checked={checked} toggle={this.toggleTemplate} />));
        templateMenu.push(<OtherToggle key={'default'} name={'Default'} checked={templateName === 'layout'} toggle={this.toggleDefault} />);
        addedTypes.concat(noteTypes).map(template => (template.treeView_Checked = this.templateIsUsed(firstDoc, template)));
        this._addedKeys &&
            Array.from(this._addedKeys)
                .filter(key => !noteTypes.some(nt => nt.title === key))
                .forEach(template => templateMenu.push(<OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
        return (
            <ul className="template-list" style={{ display: 'block' }}>
                {Doc.noviceMode ? null : <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress} />}
                {templateMenu}
                <CollectionTreeView
                    Document={Doc.MyTemplates}
                    styleProvider={DefaultStyleProvider}
                    setHeight={returnFalse}
                    docViewPath={returnEmptyDoclist}
                    childFilters={returnEmptyFilter}
                    childFiltersByRanges={returnEmptyFilter}
                    searchFilterDocs={returnEmptyDoclist}
                    onCheckedClick={this.scriptField}
                    onChildClick={this.scriptField}
                    isAnyChildContentActive={returnFalse}
                    isContentActive={returnTrue}
                    bringToFront={emptyFunction}
                    focus={emptyFunction}
                    whenChildContentsActiveChanged={emptyFunction}
                    ScreenToLocalTransform={Transform.Identity}
                    isSelected={returnFalse}
                    pinToPres={emptyFunction}
                    select={emptyFunction}
                    renderDepth={1}
                    addDocTab={returnFalse}
                    PanelWidth={this.return100}
                    PanelHeight={this.return100}
                    treeViewHideHeaderFields={true}
                    treeViewHideTitle={true}
                    dontRegisterView={true}
                    fieldKey={'data'}
                    moveDocument={returnFalse}
                    removeDocument={returnFalse}
                    addDocument={returnFalse}
                />
            </ul>
        );
    }
}

ScriptingGlobals.add(function switchView(doc: Doc, template: Doc | undefined) {
    if (template?.dragFactory) {
        template = Cast(template.dragFactory, Doc, null);
    }
    const templateTitle = StrCast(template?.title);
    return templateTitle && DocUtils.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template);
});
