import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
import { ScriptField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { SelectionManager } from '../../../util/SelectionManager';
import { undoable, UndoManager } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { DocComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
import { StyleProp } from '../../StyleProvider';
import { FieldView, FieldViewProps } from '../FieldView';
import { OpenWhere } from '../DocumentView';
import { RichTextMenu } from '../formattedText/RichTextMenu';
import './FontIconBox.scss';
import { SelectedDocView } from '../../selectedDoc';
import { Utils } from '../../../../Utils';

export enum ButtonType {
    TextButton = 'textBtn',
    MenuButton = 'menuBtn',
    DropdownList = 'dropdownList',
    DropdownButton = 'dropdownBtn',
    ClickButton = 'clickBtn',
    ToggleButton = 'toggleBtn',
    ColorButton = 'colorBtn',
    ToolButton = 'toolBtn',
    MultiToggleButton = 'multiToggleBtn',
    NumberSliderButton = 'numSliderBtn',
    NumberDropdownButton = 'numDropdownBtn',
    NumberInlineButton = 'numInlineBtn',
    EditableText = 'editableText',
}

export interface ButtonProps extends FieldViewProps {
    type?: ButtonType;
}
@observer
export class FontIconBox extends DocComponent<ButtonProps>() {
    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(FontIconBox, fieldKey);
    }
    @observable noTooltip = false;
    showTemplate = (): void => {
        const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
        dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight);
    };
    dragAsTemplate = (): void => {
        this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
    };
    useAsPrototype = (): void => {
        this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)');
    };

    specificContextMenu = (): void => {
        if (!Doc.noviceMode) {
            const cm = ContextMenu.Instance;
            cm.addItem({ description: 'Show Template', event: this.showTemplate, icon: 'tag' });
            cm.addItem({ description: 'Use as Render Template', event: this.dragAsTemplate, icon: 'tag' });
            cm.addItem({ description: 'Use as Prototype', event: this.useAsPrototype, icon: 'tag' });
        }
    };

    static GetShowLabels() {
        return BoolCast(Doc.UserDoc()._showLabel);
    }
    static SetShowLabels(show: boolean) {
        Doc.UserDoc()._showLabel = show;
    }
    static GetRecognizeGestures() {
        return BoolCast(Doc.UserDoc()._recognizeGestures);
    }
    static SetRecognizeGestures(show: boolean) {
        Doc.UserDoc()._recognizeGestures = show;
    }

    // Determining UI Specs
    @computed get label() {
        return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
    }
    Icon = (color: string, iconFalse?: boolean) => {
        let icon;
        if (iconFalse) {
            icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any;
            if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />;
            else return null;
        }
        icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
        const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />;
        return !icon ? null : icon === 'pres-trail' ? trailsIcon() : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />;
    };
    @computed get dropdown() {
        return BoolCast(this.rootDoc.dropDownOpen);
    }
    @computed get buttonList() {
        return StrListCast(this.rootDoc.btnList);
    }
    @computed get type() {
        return StrCast(this.rootDoc.btnType);
    }

    /**
     * Types of buttons in dash:
     * - Main menu button (LHS)
     * - Tool button
     * - Expandable button (CollectionLinearView)
     * - Button inside of CollectionLinearView vs. outside of CollectionLinearView
     * - Action button
     * - Dropdown button
     * - Color button
     * - Dropdown list
     * - Number button
     **/

    _batch: UndoManager.Batch | undefined = undefined;
    /**
     * Number button
     */
    @computed get numberDropdown() {
        let type: NumberDropdownType;
        switch (this.type) {
            case ButtonType.NumberDropdownButton:
                type = 'dropdown';
                break;
            case ButtonType.NumberInlineButton:
                type = 'input';
                break;
            case ButtonType.NumberSliderButton:
            default:
                type = 'slider';
                break;
        }
        const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined });
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        // Script for checking the outcome of the toggle
        const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)));
        const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;

        return (
            <NumberDropdown
                color={color}
                numberDropdownType={type}
                showPlusMinus={false}
                tooltip={this.label}
                type={Type.PRIM}
                min={NumCast(this.rootDoc.numBtnMin, 0)}
                max={NumCast(this.rootDoc.numBtnMax, 100)}
                number={checkResult}
                setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}
                fillWidth
            />
        );
    }

    /**
     * Dropdown button
     */
    @computed get dropdownButton() {
        const active: string = StrCast(this.rootDoc.dropDownOpen);
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
        return (
            <div
                className={`menuButton ${this.type} ${active}`}
                style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }}
                onClick={action(() => {
                    this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
                    this.noTooltip = this.rootDoc.dropDownOpen;
                    Doc.UnBrushAllDocs();
                })}>
                {this.Icon(color)}
                {!this.label || !FontIconBox.GetShowLabels() ? null : (
                    <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}>
                        {' '}
                        {this.label}{' '}
                    </div>
                )}
                <div className="menuButton-dropdown" style={{ borderBottomRightRadius: this.dropdown ? 0 : undefined }}>
                    <FontAwesomeIcon icon={'caret-down'} color={color} size="sm" />
                </div>
                {this.rootDoc.dropDownOpen ? <div className="menuButton-dropdownBox">{/* DROPDOWN BOX CONTENTS */}</div> : null}
            </div>
        );
    }

    /**
     * Dropdown list
     */
    @computed get dropdownListButton() {
        const active: string = StrCast(this.rootDoc.dropDownOpen);
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);

        const script = ScriptCast(this.rootDoc.script);

        let noviceList: string[] = [];
        let text: string | undefined;
        let dropdown = true;
        let getStyle: (val: string) => any = () => {};
        let icon: IconProp = 'caret-down';
        let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView');
        try {
            if (isViewDropdown) {
                const selectedDocs: Doc[] = SelectionManager.Docs();
                const selected = SelectionManager.Docs().lastElement();
                console.log('selected');
                if (selected) {
                    if (StrCast(selected.type) === DocumentType.COL) {
                        text = StrCast(selected._type_collection);
                        console.log('collection selected', text);
                    } else {
                        console.log('doc selected', selected.title);
                        dropdown = false;
                        if (selectedDocs.length > 1) {
                            text = selectedDocs.length + ' selected';
                        } else {
                            text = Utils.cleanDocumentType(StrCast(selected.type) as DocumentType);
                            icon = Doc.toIcon(selected);
                        }
                        return <Popup icon={<FontAwesomeIcon size={'1x'} icon={icon} />} text={text} type={Type.TERT} color={color} popup={<SelectedDocView selectedDocs={selectedDocs} />} fillWidth />;
                    }
                } else {
                    dropdown = false;
                    return <Button text={`None Selected`} type={Type.TERT} color={color} fillWidth inactive />;
                }
                noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
            } else {
                text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
                getStyle = (val: string) => {
                    return { fontFamily: val };
                };
            }
        } catch (e) {
            console.log(e);
        }

        console.log('current item: ', text);

        // Get items to place into the list
        const list: IListItemProps[] = this.buttonList
            .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value))
            .map(value => ({
                text: value.charAt(0).toUpperCase() + value.slice(1),
                val: value,
                style: getStyle(value),
                onClick: undoable(() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), value),
                // shortcut: '#',
            }));

        return (
            <Dropdown
                selectedVal={text}
                setSelectedVal={undoable(val => script.script.run({ this: this.layoutDoc, self: this.rootDoc, val }), `dropdown select ${this.label}`)}
                color={color}
                type={isViewDropdown ? Type.TERT : Type.PRIM}
                dropdownType={DropdownType.SELECT}
                items={list}
                tooltip={this.label}
                fillWidth
            />
        );
    }

    @computed get colorScript() {
        return ScriptCast(this.rootDoc.script);
    }

    /**
     * Color button
     */
    @computed get colorButton() {
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
        const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent';
        const tooltip: string = StrCast(this.rootDoc.toolTip);

        return (
            <ColorPicker
                setSelectedColor={value => {
                    const s = this.colorScript;
                    s && undoable(() => s.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)();
                }}
                selectedColor={curColor}
                type={Type.PRIM}
                color={color}
                icon={this.Icon(color)!}
                tooltip={tooltip}
                label={this.label}
            />
        );
    }

    @computed get toggleButton() {
        // Determine the type of toggle button
        const buttonText: string = StrCast(this.rootDoc.buttonText);
        const tooltip: string = StrCast(this.rootDoc.toolTip);

        const script = ScriptCast(this.rootDoc.onClick);
        const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false;
        // Colors
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);

        return (
            <Toggle
                tooltip={`Toggle ${tooltip}`}
                toggleType={ToggleType.BUTTON}
                type={Type.PRIM}
                toggleStatus={toggleStatus}
                text={buttonText}
                color={color}
                icon={this.Icon(color)!}
                label={this.label}
                onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })}
            />
        );
    }

    /**
     * Default
     */
    @computed get defaultButton() {
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
        const tooltip: string = StrCast(this.rootDoc.toolTip);

        return <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label} />;
    }

    @computed get editableText() {
        // Script for running the toggle
        const script = ScriptCast(this.rootDoc.script);
        // Function to run the script
        const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result;

        const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result;

        return <EditableText editing={false} setEditing={(editing: boolean) => {}} />;

        return (
            <div className="menuButton editableText">
                <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} />
                <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}>
                    <EditableView GetValue={() => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
                </div>
            </div>
        );
    }

    render() {
        // determine dash button metadata
        const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
        const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
        const tooltip: string = StrCast(this.rootDoc.toolTip);
        const onClickScript = ScriptCast(this.rootDoc.onClick);
        const script = ScriptCast(this.rootDoc.script);
        // TODO:glr Add label of button type
        let button: JSX.Element = this.defaultButton;
        // prettier-ignore
        switch (this.type) {
            case ButtonType.EditableText: 
                button = this.editableText;
                break;
            case ButtonType.DropdownList:
                button = this.dropdownListButton;
                break;
            case ButtonType.ColorButton: 
                button = this.colorButton; 
                break;
            case ButtonType.NumberDropdownButton: 
            case ButtonType.NumberInlineButton:
            case ButtonType.NumberSliderButton: 
                button = this.numberDropdown; 
                break;
            case ButtonType.DropdownButton: 
                button = this.dropdownButton; 
                break;
            case ButtonType.ToggleButton: button = this.toggleButton; break;
            case ButtonType.ClickButton:
            case ButtonType.ToolButton: 
                button = (
                    <IconButton tooltip={tooltip} 
                    color={color} icon={this.Icon(color)!} label={this.label}/>
                );
                break;
            case ButtonType.TextButton: 
                button = (
                    <Button tooltip={tooltip} icon={this.Icon(color)!} text={StrCast(this.rootDoc.buttonText)} label={this.label}/>
                );
                break;
            case ButtonType.MenuButton: button = (
                    <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false })} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/>
                );
                break;
        }

        return button;
    }
}
