import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import { AiOutlineColumnWidth } from 'react-icons/ai';
import { BiHide, BiShow } from 'react-icons/bi';
import { BsGrid3X3GapFill } from 'react-icons/bs';
import { CiGrid31 } from 'react-icons/ci';
import { FaBraille, FaLock, FaLockOpen } from 'react-icons/fa';
import { MdClosedCaption, MdClosedCaptionDisabled, MdGridOff, MdGridOn, MdSubtitles, MdSubtitlesOff, MdTouchApp } from 'react-icons/md';
import { RxWidth } from 'react-icons/rx';
import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb';
import { TfiBarChart } from 'react-icons/tfi';
import { Doc, DocListCast, Opt } from '../../fields/Doc';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
import { BoolCast, ScriptCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
import { DocUtils } from '../documents/Documents';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { IsFollowLinkScript } from '../util/LinkFollower';
import { LinkManager } from '../util/LinkManager';
import { SelectionManager } from '../util/SelectionManager';
import { SettingsManager } from '../util/SettingsManager';
import { undoable, undoBatch } from '../util/UndoManager';
import { Colors } from './global/globalEnums';
import { InkingStroke } from './InkingStroke';
import { DocumentView, OpenWhere } from './nodes/DocumentView';
import './PropertiesButtons.scss';
import React = require('react');

enum UtilityButtonState {
    Default,
    OpenRight,
    OpenExternally,
}

@observer
export class PropertiesButtons extends React.Component<{}, {}> {
    @observable public static Instance: PropertiesButtons;

    @computed get selectedDoc() {
        return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.Document;
    }
    @computed get selectedLayoutDoc() {
        return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.layoutDoc;
    }
    @computed get selectedTabView() {
        return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost;
    }

    propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
        const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc;
        const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true);
        return !targetDoc ? null : (
            <Toggle
                toggleStatus={BoolCast(targetDoc[property])}
                tooltip={tooltip(BoolCast(targetDoc[property]))}
                text={label(targetDoc?.[property])}
                color={SettingsManager.userColor}
                icon={icon(targetDoc?.[property] as any)}
                iconPlacement="left"
                align="flex-start"
                fillWidth={true}
                toggleType={ToggleType.BUTTON}
                onClick={undoable(() => {
                    if (SelectionManager.Views().length > 1) {
                        SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.Document, property));
                    } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
                }, property)}
            />
        );
    };

    // this implments a container pattern by marking the targetDoc (collection) as a lightbox
    // that always fits its contents to its container and that hides all other documents when
    // a link is followed that targets a 'lightbox' destination
    @computed get isLightboxButton() {
        return this.propertyToggleBtn(
            on => 'Lightbox',
            'isLightbox',
            on => `${on ? 'Set' : 'Remove'} lightbox flag`,
            on => 'window-restore',
            onClick => {
                SelectionManager.Views().forEach(dv => {
                    const containerDoc = dv.Document;
                    //containerDoc.followAllLinks =
                    // containerDoc.noShadow =
                    // containerDoc.layout_disableBrushing =
                    // containerDoc._forceActive =
                    //containerDoc._freeform_fitContentsToBox =
                    containerDoc._isLightbox = !containerDoc._isLightbox;
                    //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                    const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
                    //dv.Docuemnt.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false)));
                });
            }
        );
    }

    @computed get titleButton() {
        return this.propertyToggleBtn(
            on => (!on ? 'SHOW TITLE' : this.selectedDoc?.['_layout_showTitle'] === 'title:hover' ? 'HIDE TITLE' : 'HOVER TITLE'),
            '_layout_showTitle',
            on => 'Switch between title styles',
            on => (on ? <MdSubtitlesOff /> : <MdSubtitles />), // {currentIcon}, //(on ?  <MdSubtitles/> :)  , //,'text-width', on ?  <MdSubtitles/> : <MdSubtitlesOff/>,
            (dv, doc) => {
                const tdoc = dv?.Document || doc;
                const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : '';
                tdoc._layout_showTitle = newtitle ? newtitle : undefined;
            }
        );
    }

    @computed get lockButton() {
        return this.propertyToggleBtn(
            on => (on ? 'UNLOCK' : 'LOCK'), // 'No\xA0Drag',
            '_lockedPosition',
            on => `${on ? 'Unlock' : 'Lock'} position to prevent dragging`,
            on => (on ? <FaLockOpen /> : <FaLock />)
            // on => 'thumbtack'
        );
    }

    @computed get maskButton() {
        //highlight text while going down and reading through
        return this.propertyToggleBtn(
            on => (on ? 'PLAIN INK' : 'HIGHLIGHTER MASK'),
            'stroke_isInkMask',
            on => (on ? 'Make plain ink' : 'Make highlight mask'),
            on => (on ? <TbHighlightOff /> : <TbHighlight />), // <FaHighlighter/>,// 'paint-brush',
            (dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc)
        );
    }

    @computed get hideImageButton() {
        // put in developer -- can trace on top of object and drawing is still there
        return this.propertyToggleBtn(
            on => (on ? 'SHOW BACKGROUND IMAGE' : 'HIDE BACKGROUND IMAGE'), //'Background',
            '_hideImage',
            on => (on ? 'Show Image' : 'Show Background'),
            on => (on ? <BiShow /> : <BiHide />) //'portrait'
        );
    }

    @computed get clustersButton() {
        return this.propertyToggleBtn(
            on => (on ? 'DISABLE CLUSTERS' : 'HIGHLIGHT CLUSTERS'),
            '_freeform_useClusters',
            on => `${on ? 'Hide' : 'Show'} clusters`,
            on => <FaBraille />
        );
    }
    @computed get panButton() {
        return this.propertyToggleBtn(
            on => (on ? 'ENABLE PANNING' : 'DISABLE PANNING'), //'Lock\xA0View',
            '_lockedTransform',
            on => `${on ? 'Unlock' : 'Lock'} panning of view`,
            on => (on ? <TbHandStop /> : <TbHandOff />) //'lock'
        );
    }

    @computed get forceActiveButton() {
        //select text
        return this.propertyToggleBtn(
            on => (on ? 'SELECT TO INTERACT' : 'ALWAYS INTERACTIVE'),
            '_forceActive',
            on => `${on ? 'Document must be selected to interact with its contents' : 'Contents always active (respond to click/drag events)'} `,
            on => <MdTouchApp /> // 'eye'
        );
    }

    @computed get verticalAlignButton() {
        //select text
        return this.propertyToggleBtn(
            on => (on ? 'ALIGN TOP' : 'ALIGN CENTER'),
            '_layout_centered',
            on => `${on ? 'Text is aligned with top of document' : 'Text is aligned with center of document'} `,
            on => <MdTouchApp /> // 'eye'
        );
    }

    @computed get fitContentButton() {
        return this.propertyToggleBtn(
            on => (on ? 'PREVIOUS VIEW' : 'VIEW ALL'), //'View All',
            '_freeform_fitContentsToBox',
            on => `${on ? "Don't" : 'Do'} fit content to container visible area`,
            on => (on ? <CiGrid31 /> : <BsGrid3X3GapFill />) //'object-group'
        );
    }

    // // this implments a container pattern by marking the targetDoc (collection) as a lightbox
    // // that always fits its contents to its container and that hides all other documents when
    // // a link is followed that targets a 'lightbox' destination
    // @computed get isLightboxButton() { // developer
    //     return this.propertyToggleBtn(
    //         on => 'Lightbox',
    //         'isLightbox',
    //         on => `${on ? 'Set' : 'Remove'} lightbox flag`,
    //         on => 'window-restore',
    //         onClick => {
    //             SelectionManager.Views().forEach(dv => {
    //                 const containerDoc = dv.Document;
    //                 //containerDoc.followAllLinks =
    //                 // containerDoc.noShadow =
    //                 // containerDoc.disableDocBrushing =
    //                 // containerDoc._forceActive =
    //                 //containerDoc._freeform_fitContentsToBox =
    //                 containerDoc._isLightbox = !containerDoc._isLightbox;
    //                 //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
    //                 const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
    //                 //dv.Document.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
    //                 containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
    //             });
    //         }
    //     );
    // }

    @computed get layout_fitWidthButton() {
        return this.propertyToggleBtn(
            on => (on ? 'SCALED VIEW' : 'READING VIEW'), //'Fit\xA0Width',
            '_layout_fitWidth',
            on =>
                on
                    ? "Scale document so it's width and height fit container (no effect when document is viewed on freeform canvas)"
                    : "Scale document so it's width fits container and its height expands/contracts to fit available space  (no effect when document is viewed on freeform canvas)",
            on => (on ? <AiOutlineColumnWidth /> : <RxWidth />) // 'arrows-alt-h'
        );
    }

    @computed get captionButton() {
        return this.propertyToggleBtn(
            //DEVELOPER
            on => (on ? 'HIDE CAPTION' : 'SHOW CAPTION'), //'Caption',
            '_layout_showCaption',
            on => `${on ? 'Hide' : 'Show'} caption footer`,
            on => (on ? <MdClosedCaptionDisabled /> : <MdClosedCaption />), //'closed-captioning',
            (dv, doc) => ((dv?.Document || doc)._layout_showCaption = (dv?.Document || doc)._layout_showCaption === undefined ? 'caption' : undefined)
        );
    }

    @computed get chromeButton() {
        // developer -- removing UI decoration
        return this.propertyToggleBtn(
            on => (on ? 'ENABLE UI CONTROLS' : 'DISABLE UI CONTROLS'),
            '_chromeHidden',
            on => `${on ? 'Show' : 'Hide'} editing UI`,
            on => (on ? <TbEditCircle /> : <TbEditCircleOff />), // 'edit',
            (dv, doc) => ((dv?.Document || doc)._chromeHidden = !(dv?.Document || doc)._chromeHidden)
        );
    }

    @computed get layout_autoHeightButton() {
        // store previous dimensions to store old values
        return this.propertyToggleBtn(
            on => (on ? 'AUTO\xA0SIZE' : 'FIXED SIZE'),
            '_layout_autoHeight',
            on => `Automatical vertical sizing to show all content`,
            on => <FontAwesomeIcon icon="arrows-alt-v" size="lg" />
        );
    }

    @computed get gridButton() {
        return this.propertyToggleBtn(
            on => (on ? 'HIDE GRID' : 'DISPLAY GRID'),
            '_freeform_backgroundGrid',
            on => `Display background grid in collection`,
            on => (on ? <MdGridOff /> : <MdGridOn />) //'border-all'
        );
    }

    // @computed get groupButton() { //developer
    //     return this.propertyToggleBtn(
    //         on => 'Group',
    //         'isGroup',
    //         on => `Display collection as a Group`,
    //         on => 'object-group',
    //         (dv, doc) => {
    //             doc.isGroup = !doc.isGroup;
    //             doc.forceActive = doc.isGroup;
    //         }
    //     );
    // }

    // @computed get freezeThumb() {
    //     return this.propertyToggleBtn(
    //         'FreezeThumb',
    //         '_thumb-frozen',
    //         on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`,
    //         on => 'snowflake',
    //         (dv, doc) => {
    //             if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined;
    //             else {
    //                 document.body.focus(); // so that we can access the clipboard without an error
    //                 setTimeout(() =>
    //                     pasteImageBitmap((data_url: any, error: any) => {
    //                         error && console.log(error);
    //                         data_url && Utils.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
    //                     })
    //                 );
    //             }
    //         }
    //     );
    // }
    @computed get snapButton() {
        // THESE ARE NOT COMING
        return this.propertyToggleBtn(
            on => (on ? 'HIDE SNAP LINES' : 'SHOW SNAP LINES'),
            'freeform_snapLines',
            on => `Display snapping lines when objects are dragged`,
            on => <TfiBarChart />, //'th',
            undefined
        );
    }

    // @computed
    // get onClickButton() {
    //     return !this.selectedDoc ? null : (
    //         <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
    //             <div>
    //                 <div className="propertiesButtons-linkFlyout">
    //                     <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
    //                         <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
    //                             <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
    //                         </div>
    //                     </Flyout>
    //                 </div>
    //                 <div className="propertiesButtons-title"> onclick </div>
    //             </div>
    //         </Tooltip>
    //     );
    // }
    // @computed
    // get perspectiveButton() { // gone
    //     return !this.selectedDoc ? null : (
    //         <Tooltip title={<div className="dash-tooltip">Choose view perspective</div>} placement="top">
    //             <div>
    //                 <div className="propertiesButtons-linkFlyout">
    //                     <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onPerspectiveFlyout}>
    //                         <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
    //                             <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
    //                         </div>
    //                     </Flyout>
    //                 </div>
    //                 <div className="propertiesButtons-title"> Perspective </div>
    //             </div>
    //         </Tooltip>
    //     );
    // }

    @undoBatch
    handlePerspectiveChange = (e: any) => {
        this.selectedDoc && (this.selectedDoc._type_collection = e.target.value);
        SelectionManager.Views()
            .filter(dv => dv.docView)
            .map(dv => dv.docView!)
            .forEach(docView => (docView.layoutDoc._type_collection = e.target.value));
    };
    @computed get onClickVal() {
        const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
        const followLoc = this.selectedDoc._followLinkLocation;
        const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox);

        if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace';
        else if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight';
        else if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal';
        else if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail';
        else return 'nothing';
    }

    @computed
    get onClickButton() {
        const buttonList = [
            ['nothing', 'Select Document'],
            ['enterPortal', 'Enter Portal'],
            ['toggleDetail', 'Toggle Detail'],
            ['linkInPlace', 'Open Link in Lightbox'],
            ['linkOnRight', 'Open Link on Right'],
        ];

        const items: IListItemProps[] = buttonList.map(value => {
            return {
                text: value[1],
                val: value[1],
            };
        });
        return !this.selectedDoc ? null : (
            <Dropdown
                tooltip={'Choose onClick behavior'}
                items={items}
                closeOnSelect={true}
                selectedVal={this.onClickVal}
                setSelectedVal={val => this.handleOptionChange(val as string)}
                title={'Choose onClick behaviour'}
                color={SettingsManager.userColor}
                dropdownType={DropdownType.SELECT}
                type={Type.SEC}
                fillWidth
            />
            // <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
            //     <div>
            //         <div className="propertiesButtons-linkFlyout">
            //             <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
            //                 <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
            //                     <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
            //                 </div>
            //             </Flyout>
            //         </div>
            //         <div className="propertiesButtons-title"> onclick </div>
            //     </div>
            // </Tooltip>
        );
    }

    @undoBatch
    @action
    handleOptionChange = (onClick: string) => {
        SelectionManager.Views()
            .filter(dv => dv.docView)
            .map(dv => dv.docView!)
            .forEach(docView => {
                const linkButton = IsFollowLinkScript(docView.props.Document.onClick);
                docView.noOnClick();
                switch (onClick) {
                    case 'enterPortal':
                        docView.makeIntoPortal();
                        break;
                    case 'toggleDetail':
                        docView.setToggleDetail();
                        break;
                    case 'linkInPlace':
                        docView.toggleFollowLink(false, false);
                        docView.props.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined;
                        break;
                    case 'linkOnRight':
                        docView.toggleFollowLink(false, false);
                        docView.props.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined;
                        break;
                }
            });
    };

    @undoBatch
    editOnClickScript = () => {
        if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => DocUtils.makeCustomViewClicked(dv.Document, undefined, 'onClick'));
        else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick');
    };

    @computed
    get onClickFlyout() {
        const buttonList = [
            ['nothing', 'Select Document'],
            ['enterPortal', 'Enter Portal'],
            ['toggleDetail', 'Toggle Detail'],
            ['linkInPlace', 'Open Link in Lightbox'],
            ['linkOnRight', 'Open Link on Right'],
        ];
        const list = buttonList.map(value => {
            const click = () => this.handleOptionChange(value[0]);
            const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
            const followLoc = this.selectedDoc._followLinkLocation;
            const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox);

            let active = false;
            // prettier-ignore
            switch (value[0]) {
                case 'linkInPlace': active = linkButton && followLoc === OpenWhere.lightbox && !linkedToLightboxView();  break;
                case 'linkOnRight': active = linkButton && followLoc === OpenWhere.addRight; break;
                case 'enterPortal': active = linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView(); break;
                case 'toggleDetail':active = ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail'); break;
                case 'nothing':     active = !linkButton && this.selectedDoc.onClick === undefined;break;
            }
            return (
                <div className="list-item" key={`${value}`} style={{ backgroundColor: active ? Colors.LIGHT_BLUE : undefined }} onClick={click}>
                    {value[1]}
                </div>
            );
        });
        return (
            <div>
                <div>
                    <div className="propertiesButton-dropdownList">{list}</div>
                </div>
                {Doc.noviceMode ? null : (
                    <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript">
                        {' '}
                        Edit onClick Script
                    </div>
                )}
            </div>
        );
    }

    render() {
        const layoutField = this.selectedDoc?.[Doc.LayoutFieldKey(this.selectedDoc)];
        const isText = layoutField instanceof RichTextField;
        const isInk = this.selectedDoc?.layout_isSvg;
        const isImage = layoutField instanceof ImageField;
        const isMap = this.selectedDoc?.type === DocumentType.MAP;
        const isCollection = this.selectedDoc?.type === DocumentType.COL;
        //TODO: will likely need to create separate note-taking view type here
        const isStacking = this.selectedDoc?._type_collection === CollectionViewType.Stacking || this.selectedDoc?._type_collection === CollectionViewType.NoteTaking;
        const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform;
        const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree;
        const isTabView = this.selectedTabView;
        const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => (
            <div className="propertiesButtons-button" style={style}>
                {' '}
                {ele}{' '}
            </div>
        );
        const isNovice = Doc.noviceMode;
        return !this.selectedDoc ? null : (
            <div className="propertiesButtons">
                {toggle(this.titleButton)}
                {toggle(this.captionButton)}
                {toggle(this.lockButton)}
                {/* {toggle(this.onClickButton)} */}
                {toggle(this.layout_fitWidthButton)}
                {/* {toggle(this.freezeThumb)} */}
                {toggle(this.forceActiveButton)}
                {toggle(this.verticalAlignButton, { display: !isText ? 'none' : '' })}
                {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
                {/* {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })} */}
                {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
                {toggle(this.maskButton, { display: isNovice || !isInk ? 'none' : '' })}
                {toggle(this.hideImageButton, { display: !isImage ? 'none' : '' })}
                {toggle(this.chromeButton, { display: isNovice ? 'none' : '' })}
                {toggle(this.gridButton, { display: !isCollection ? 'none' : '' })}
                {/* {toggle(this.groupButton, { display: isTabView || !isCollection ? 'none' : '' })} */}
                {toggle(this.snapButton, { display: !isCollection ? 'none' : '' })}
                {toggle(this.clustersButton, { display: !isFreeForm ? 'none' : '' })}
                {toggle(this.panButton, { display: !isFreeForm ? 'none' : '' })}
            </div>
        );
    }
}
