import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from '@dash/components';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from '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, Opt } from '../../fields/Doc';
import { ScriptField } from '../../fields/ScriptField';
import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { SettingsManager } from '../util/SettingsManager';
import { undoBatch, undoable } from '../util/UndoManager';
import { InkingStroke } from './InkingStroke';
import './PropertiesButtons.scss';
import { Colors } from './global/globalEnums';
import { DocumentView } from './nodes/DocumentView';
import { OpenWhere } from './nodes/OpenWhere';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';

@observer
export class PropertiesButtons extends React.Component {
    // eslint-disable-next-line no-use-before-define
    @observable public static Instance: PropertiesButtons;

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

    @computed get titleButton() {
        return this.propertyToggleBtn(
            on => (!on ? 'SHOW TITLE' : this.selectedDoc?._layout_showTitle === 'title:hover' ? 'HIDE TITLE' : 'HOVER TITLE'),
            '_layout_showTitle',
            () => '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 || 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`,
            () => <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)'} `,
            () => <MdTouchApp /> // 'eye'
        );
    }

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

    @computed get flashcardButton() {
        return this.propertyToggleBtn(
            on => (on ? 'DISABLE FLASHCARD' : 'ENABLE FLASHCARD'),
            'layout_textPainted',
            on => `${on ? 'Flashcard enabled' : 'Flashcard disabled'} `,
            () => <MdTouchApp />,
            (dv, doc) => {
                const on = !!doc.$onPaint;
                doc.$onPaint = on ? undefined : ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, { documentView: 'any' });
                doc.$layout_textPainted = on ? undefined : `<ComparisonBox {...props} fieldKey={'${dv?.LayoutFieldKey ?? 'text'}'}/>`;
            }
        );
    }

    @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 => {
    //             DocumentView.Selected().forEach(dv => {
    //                 const containerDoc = dv.Document;
    //                 //containerDoc.followAllLinks =
    //                 // containerDoc.noShadow =
    //                 // containerDoc.disableDocBrushing =
    //                 // containerDoc._forceActive =
    //                 //containerDoc._freeform_fitContentsToBox =
    //                 containerDoc._isLightbox = !containerDoc._isLightbox;
    //                 //containerDoc._xMargin = containerDoc._yMargin = containerDoc._isLightbox ? 10 : undefined;
    //                 const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
    //                 //dv.Document.onClick = ScriptField.MakeScript('{this.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',
            () => `Automatical vertical sizing to show all content`,
            () => <FontAwesomeIcon icon="arrows-alt-v" size="lg" />
        );
    }

    @computed get gridButton() {
        return this.propertyToggleBtn(
            on => (on ? 'HIDE GRID' : 'DISPLAY GRID'),
            '_freeform_backgroundGrid',
            () => `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) => {
    //             docfreeform_isGroup = !docfreeform_isGroup;
    //             doc.forceActive = docfreeform_isGroup;
    //         }
    //     );
    // }

    @computed get snapButton() {
        // THESE ARE NOT COMING
        return this.propertyToggleBtn(
            on => (on ? 'HIDE SNAP LINES' : 'SHOW SNAP LINES'),
            'freeform_snapLines',
            () => `Display snapping lines when objects are dragged`,
            () => <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>
    //     );
    // }

    @computed get onClickVal() {
        const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
        const followLoc = this.selectedDoc._followLinkLocation;
        const linkedToLightboxView = () => Doc.Links(this.selectedDoc).some(link => Doc.getOppositeAnchor(link, this.selectedDoc)?.$isLightbox);

        if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace';
        if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight';
        if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal';
        if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail';
        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 => ({
            text: value[1],
            val: value[1],
        }));
        return !this.selectedDoc ? null : (
            <Dropdown
                tooltip="Choose onClick behavior"
                items={items}
                closeOnSelect
                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) => {
        DocumentView.Selected().forEach(docView => {
            const linkButton = IsFollowLinkScript(docView.Document.onClick);
            docView.noOnClick();
            switch (onClick) {
                case 'enterPortal':
                    DocUtils.makeIntoPortal(docView.Document, docView.layoutDoc, docView.allLinks);
                    break;
                case 'toggleDetail':
                    docView.setToggleDetail();
                    break;
                case 'linkInPlace':
                    docView.toggleFollowLink(false, false);
                    docView.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined;
                    break;
                case 'linkOnRight':
                    docView.toggleFollowLink(false, false);
                    docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined;
                    break;
                default:
            }
        });
    };

    @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 = () => Doc.Links(this.selectedDoc).some(link => Doc.getOppositeAnchor(link, this.selectedDoc)?._isLightbox);

            const active = () => {
                // prettier-ignore
                switch (value[0]) {
                    case 'linkInPlace': return linkButton && followLoc === OpenWhere.lightbox && !linkedToLightboxView();  break;
                    case 'linkOnRight': return linkButton && followLoc === OpenWhere.addRight; break;
                    case 'enterPortal': return linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView(); break;
                    case 'toggleDetail':return ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail'); break;
                    case 'nothing':    return !linkButton && this.selectedDoc.onClick === undefined;break;
                    default: return false;
                }
            };
            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>
        );
    }
    @undoBatch
    editOnClickScript = () => {
        if (DocumentView.Selected().length) DocumentView.Selected().forEach(dv => DocUtils.makeCustomViewClicked(dv.Document, undefined, 'onClick'));
        else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick');
    };

    propertyToggleBtn = (label: (on?: unknown) => string, property: string, tooltip: (on?: unknown) => string, icon: (on?: unknown) => unknown, 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];
        };
        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 string}
                iconPlacement="left"
                align="flex-start"
                fillWidth
                toggleType={ToggleType.BUTTON}
                onClick={undoable(() => {
                    if (DocumentView.Selected().length > 1) {
                        DocumentView.Selected().forEach(dv => (onClick ?? onPropToggle)(dv, dv.Document, property));
                    } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
                }, property)}
            />
        );
    };

    render() {
        const layoutField = this.selectedDoc?.[Doc.LayoutDataKey(this.selectedDoc)];
        const isText = DocumentView.Selected().lastElement()?.ComponentView instanceof FormattedTextBox;
        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;
        const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(StrCast(this.selectedDoc?._type_collection) as CollectionViewType);
        const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform;
        const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree;
        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.flashcardButton, { 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>
        );
    }
}
