import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
import { Doc } from '../../../../fields/Doc';
import { DocCast, ImageCast } from '../../../../fields/Types';
import { ImageField } from '../../../../fields/URLField';
import { emptyFunction } from '../../../../Utils';
import { SnappingManager } from '../../../util/SnappingManager';
import { undoable } from '../../../util/UndoManager';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DocumentView } from '../DocumentView';
import { DataVizBox } from './DataVizBox';
import './DocCreatorMenu.scss';
import { Id } from '../../../../fields/FieldSymbols';
import { Colors } from 'browndash-components';

@observer
export class DocCreatorMenu extends ObservableReactComponent<{}> {

    static Instance: DocCreatorMenu;

    private _ref: HTMLDivElement | null = null;

    @observable _templateDocs: Doc[] = [];
    @observable _templateRefToDoc?: ObservableMap<HTMLDivElement, Doc>;
    @observable _selectedTemplateID?: Doc;

    @observable _selectedLayout?: 'stacked' | 'grid' | 'row' | 'column' | 'custom';

    @observable _pageX: number = 0;
    @observable _pageY: number = 0;
    @observable _display: boolean = false;

    @observable _mouseX: number = -1;
    @observable _mouseY: number = -1;
    @observable _startPos?: {x: number, y: number};
    @observable _shouldDisplay: boolean = false;

    @observable _menuContent: 'templates' | 'options' = 'templates';
    @observable _dragging: boolean = false;
    @observable _dataViz?: DataVizBox;

    constructor(props: any) {
        super(props);
        makeObservable(this);
        DocCreatorMenu.Instance = this;
    }

    @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz };
    @action setTemplateDocs = (docs: Doc[]) => {
         this._templateDocs = docs.map(doc => doc.annotationOn ? DocCast(doc.annotationOn):doc);
    };

    @action
    onPointerDown = (e: PointerEvent) => {
        this._mouseX = e.clientX;
        this._mouseY = e.clientY;
    };

    @action
    onPointerUp = (e: PointerEvent) => {
        if (e.button !== 2 && !e.ctrlKey) return;
        const curX = e.clientX;
        const curY = e.clientY;
        if (Math.abs(this._mouseX - curX) > 1 || Math.abs(this._mouseY - curY) > 1) {
            this._shouldDisplay = false;
        }
    };

    _disposer: IReactionDisposer | undefined;
    componentDidMount() {
        document.addEventListener('pointerdown', this.onPointerDown, true);
        document.addEventListener('pointerup', this.onPointerUp);
        this._disposer = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon));
    }

    componentWillUnmount() {
        this._disposer?.();
        document.removeEventListener('pointerdown', this.onPointerDown, true);
        document.removeEventListener('pointerup', this.onPointerUp);
    }

    @action
    toggleDisplay = (x: number, y: number) => {
        if (this._shouldDisplay) {
            this._shouldDisplay = false;
        } else {
            this._pageX = x;
            console.log(y);
            this._pageY = y;
            this._shouldDisplay = true;
        }
    };

    @action
    closeMenu = () => {
        const wasOpen = this._display;
        this._display = false;
        this._shouldDisplay = false;
        return wasOpen;
    };

    @action
    onPointerMove = (e: any) => {
        if (this._dragging){
            this._pageX = e.pageX - (this._startPos?.x ?? 0);
            this._pageY = e.pageY - (this._startPos?.y ?? 0);
        }
    }

    async getIcon(doc: Doc) {
        const docView = DocumentView.getDocumentView(doc);
        if (docView) {
            docView.ComponentView?.updateIcon?.();
            return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500));
        }
        return undefined;
    }

    get templatesPreviewContents(){
        const renderedTemplates: Doc[] = [];
        return (
            <div className='docCreatorMenu-preview-container'>
                {this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => {
                    if (renderedTemplates.includes(info.doc)) return undefined;
                    renderedTemplates.push(info.doc);
                    return (<div 
                    className='docCreatorMenu-preview-window'
                    style={{
                        background: this._selectedTemplateID === info.doc ? Colors.MEDIUM_BLUE : '',
                        boxShadow: this._selectedTemplateID === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
                    }}
                    onPointerDown={e =>
                        setupMoveUpEvents(this, e, returnFalse, emptyFunction,
                            undoable(clickEv => {
                                clickEv.stopPropagation();
                                this._selectedTemplateID = info.doc;
                                this.forceUpdate();
                            }, 'open actions menu')
                        )
                    }>
                        <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
                    </div>
                )})}
            </div>
        );
    }

    get optionsMenuContents(){

        const layoutOption = (option: 'stacked' | 'grid' | 'row' | 'column' | 'custom', optStyle?: {}) => {
            return (
                <div 
                    className="docCreatorMenu-dropdown-option" 
                    style={optStyle}
                    onPointerDown={e =>
                        setupMoveUpEvents(this, e, returnFalse, emptyFunction,
                            undoable(clickEv => {
                                clickEv.stopPropagation();
                                runInAction(() => this._selectedLayout = option);
                            }, 'open actions menu')
                        )
                    }>
                    {option}
                </div>
            );
        }

        return (
            <div className='docCreatorMenu-options-container'>
                <div className='docCreatorMenu-dropdown-hoverable'>
                    <div className="docCreatorMenu-dropdown-title">Choose Layout</div>
                    <div className="docCreatorMenu-dropdown-content">
                        {layoutOption('stacked')}
                        {layoutOption('grid')}
                        {layoutOption('row')}
                        {layoutOption('column')}
                        {layoutOption('custom', {borderBottom: `0px`})}
                    </div>
                </div>
                <div className='docCreatorMenu-layout-preview-window'>

                </div>
            </div>
        );
    }

    render() {
        return (
            <div
                className="docCreatorMenu-cont"
                ref={r => this._ref = r}
                style={{
                    display: '',
                    left: this._pageX,
                    top: this._pageY,
                    width: this._shouldDisplay ? 300 : 0,
                    height: this._shouldDisplay ? 400 : 0,
                    background: SnappingManager.userBackgroundColor,
                    color: SnappingManager.userColor,
                }}>
            {!this._shouldDisplay ? undefined : 
                <>
                    <div 
                    className='docCreatorMenu-menu'
                    onPointerDown={e =>
                        setupMoveUpEvents(
                            this,
                            e,
                            (e) => {
                                this._dragging = true;
                                this._startPos = {x: 0, y: 0};
                                this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0);
                                this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0);
                                return true;
                            },
                            emptyFunction,
                            undoable(clickEv => {
                                clickEv.stopPropagation();
                            }, 'drag menu')
                        )
                    }
                    onPointerMove={e => this.onPointerMove(e)}
                    onPointerUp={() => this._dragging = false}
                    >  
                        <button 
                            className='docCreatorMenu-menu-button'
                            onPointerDown={e =>
                                setupMoveUpEvents(
                                    this,
                                    e,
                                    returnFalse,
                                    emptyFunction,
                                    undoable(clickEv => {
                                        clickEv.stopPropagation();
                                        runInAction(() => this._menuContent = this._menuContent === 'templates' ? 'options' : 'templates');
                                    }, 'create docs')
                                )
                            }
                        >
                            <FontAwesomeIcon icon={this._menuContent === 'templates' ? 'bars' : 'magnifying-glass'}/>
                        </button>
                        <button className='docCreatorMenu-menu-button right'>
                            <FontAwesomeIcon icon={'plus'}/>
                        </button>
                        <button 
                            className='docCreatorMenu-menu-button close-menu'
                            onPointerDown={e =>
                                setupMoveUpEvents(
                                    this,
                                    e,
                                    returnFalse,
                                    emptyFunction,
                                    undoable(clickEv => {
                                        clickEv.stopPropagation();
                                        this.closeMenu();
                                    }, 'close menu')
                                )
                            }
                        >
                            <FontAwesomeIcon icon={'minus'}/>
                        </button>
                    </div>
                    <hr className='docCreatorMenu-menu-hr'/>
                    {this._menuContent === 'templates' ? this.templatesPreviewContents : this.optionsMenuContents}
                </>
            }
            </div>
            )
        }
    

}