import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { action, computed, IReactionDisposer, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as ReactDOM from 'react-dom/client';
import { Doc } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
import { Cast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils';
import { DocServer } from '../../../DocServer';
import { CollectionViewType } from '../../../documents/DocumentTypes';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell';
import { OpenWhere } from '../DocumentView';
import './DashFieldView.scss';
import { FormattedTextBox } from './FormattedTextBox';
import * as React from 'react';
import { Transform } from '../../../util/Transform';

export class DashFieldView {
    dom: HTMLDivElement; // container for label and value
    root: any;
    node: any;
    tbox: FormattedTextBox;

    unclickable = () => !this.tbox._props.isSelected() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview);
    constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
        this.node = node;
        this.tbox = tbox;
        this.dom = document.createElement('div');
        this.dom.style.width = node.attrs.width;
        this.dom.style.height = node.attrs.height;
        this.dom.style.position = 'relative';
        this.dom.style.display = 'inline-block';
        this.dom.onkeypress = function (e: any) {
            e.stopPropagation();
        };
        this.dom.onkeydown = function (e: any) {
            e.stopPropagation();
        };
        this.dom.onkeyup = function (e: any) {
            e.stopPropagation();
        };
        this.dom.onmousedown = function (e: any) {
            e.stopPropagation();
        };

        this.root = ReactDOM.createRoot(this.dom);
        this.root.render(
            <DashFieldViewInternal
                node={node}
                unclickable={this.unclickable}
                getPos={getPos}
                fieldKey={node.attrs.fieldKey}
                docId={node.attrs.docId}
                width={node.attrs.width}
                height={node.attrs.height}
                hideKey={node.attrs.hideKey}
                editable={node.attrs.editable}
                tbox={tbox}
            />
        );
    }
    destroy() {
        setTimeout(() => {
            try {
                this.root.unmount();
            } catch {}
        });
    }
    @action deselectNode() {
        this.dom.classList.remove('ProseMirror-selectednode');
    }
    @action selectNode() {
        this.dom.classList.add('ProseMirror-selectednode');
    }
}

interface IDashFieldViewInternal {
    fieldKey: string;
    docId: string;
    hideKey: boolean;
    tbox: FormattedTextBox;
    width: number;
    height: number;
    editable: boolean;
    node: any;
    getPos: any;
    unclickable: () => boolean;
}

@observer
export class DashFieldViewInternal extends React.Component<IDashFieldViewInternal> {
    _reactionDisposer: IReactionDisposer | undefined;
    _textBoxDoc: Doc;
    _fieldKey: string;
    _fieldStringRef = React.createRef<HTMLSpanElement>();
    @observable _dashDoc: Doc | undefined = undefined;
    @observable _expanded = false;

    constructor(props: IDashFieldViewInternal) {
        super(props);
        this._fieldKey = this.props.fieldKey;
        this._textBoxDoc = this.props.tbox.Document;

        if (this.props.docId) {
            DocServer.GetRefField(this.props.docId).then(action(dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc)));
        } else {
            this._dashDoc = this.props.tbox.Document;
        }
    }
    componentWillUnmount() {
        this._reactionDisposer?.();
    }
    return100 = () => 100;

    // set the display of the field's value (checkbox for booleans, span of text for strings)
    @computed get fieldValueContent() {
        return !this._dashDoc ? null : (
            <div onClick={action(e => (this._expanded = !this.props.editable ? !this._expanded : true))} style={{ fontSize: 'smaller', width: this.props.hideKey ? this.props.tbox.props.PanelWidth() - 20 : undefined }}>
                <SchemaTableCell
                    Document={this._dashDoc}
                    col={0}
                    deselectCell={emptyFunction}
                    selectCell={emptyFunction}
                    maxWidth={this.props.hideKey ? undefined : this.return100}
                    columnWidth={this.props.hideKey ? () => this.props.tbox._props.PanelWidth() - 20 : returnZero}
                    selectedCell={() => [this._dashDoc!, 0]}
                    fieldKey={this._fieldKey}
                    rowHeight={returnZero}
                    isRowActive={() => this._expanded && this.props.editable}
                    padding={0}
                    getFinfo={emptyFunction}
                    setColumnValues={returnFalse}
                    allowCRs={true}
                    oneLine={!this._expanded}
                    finishEdit={action(() => (this._expanded = false))}
                    transform={Transform.Identity}
                    menuTarget={null}
                />
            </div>
        );
    }

    createPivotForField = (e: React.MouseEvent) => {
        let container = this.props.tbox._props.DocumentView?.()._props.docViewPath().lastElement();
        if (container) {
            const embedding = Doc.MakeEmbedding(container.Document);
            embedding._type_collection = CollectionViewType.Time;
            const colHdrKey = '_' + container.LayoutFieldKey + '_columnHeaders';
            let list = Cast(embedding[colHdrKey], listSpec(SchemaHeaderField));
            if (!list) {
                embedding[colHdrKey] = list = new List<SchemaHeaderField>();
            }
            list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, '#f1efeb'));
            list.map(c => c.heading).indexOf('text') === -1 && list.push(new SchemaHeaderField('text', '#f1efeb'));
            embedding._pivotField = this._fieldKey.startsWith('#') ? 'tags' : this._fieldKey;
            this.props.tbox._props.addDocTab(embedding, OpenWhere.addRight);
        }
    };

    // clicking on the label creates a pivot view collection of all documents
    // in the same collection.  The pivot field is the fieldKey of this label
    onPointerDownLabelSpan = (e: any) => {
        setupMoveUpEvents(this, e, returnFalse, returnFalse, e => {
            DashFieldViewMenu.createFieldView = this.createPivotForField;
            DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16, this._fieldKey);
        });
    };

    render() {
        return (
            <div
                className="dashFieldView"
                style={{
                    width: this.props.width,
                    height: this.props.height,
                    pointerEvents: this.props.tbox._props.isSelected() || this.props.tbox.isAnyChildContentActive?.() ? undefined : 'none',
                }}>
                {this.props.hideKey ? null : (
                    <span className="dashFieldView-labelSpan" title="click to see related tags" onPointerDown={this.onPointerDownLabelSpan}>
                        {this._fieldKey}
                    </span>
                )}

                {this.props.fieldKey.startsWith('#') ? null : this.fieldValueContent}
            </div>
        );
    }
}
@observer
export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> {
    static Instance: DashFieldViewMenu;
    static createFieldView: (e: React.MouseEvent) => void = emptyFunction;
    constructor(props: any) {
        super(props);
        DashFieldViewMenu.Instance = this;
    }
    @action
    showFields = (e: React.MouseEvent) => {
        DashFieldViewMenu.createFieldView(e);
        DashFieldViewMenu.Instance.fadeOut(true);
    };

    @observable _fieldKey = '';

    @action
    public show = (x: number, y: number, fieldKey: string) => {
        this._fieldKey = fieldKey;
        this.jumpTo(x, y, true);
        const hideMenu = () => {
            this.fadeOut(true);
            document.removeEventListener('pointerdown', hideMenu, true);
        };
        document.addEventListener('pointerdown', hideMenu, true);
    };
    render() {
        return this.getElement(
            <Tooltip key="trash" title={<div className="dash-tooltip">{`Show Pivot Viewer for '${this._fieldKey}'`}</div>}>
                <button className="antimodeMenu-button" onPointerDown={this.showFields}>
                    <FontAwesomeIcon icon="eye" size="lg" />
                </button>
            </Tooltip>
        );
    }
}
