import { action, computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, Field, StrListCast } from '../../../../../fields/Doc';
import { List } from '../../../../../fields/List';
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils';
import { DragManager } from '../../../../util/DragManager';
import { DocumentView } from '../../DocumentView';
import { DataVizView } from '../DataVizBox';
import { LinkManager } from '../../../../util/LinkManager';
import { Cast, DocCast } from '../../../../../fields/Types';
import './Chart.scss';
import { listSpec } from '../../../../../fields/Schema';

interface TableBoxProps {
    rootDoc: Doc;
    layoutDoc: Doc;
    pairs: { [key: string]: any }[];
    selectAxes: (axes: string[]) => void;
    axes: string[];
    width: number;
    height: number;
    margin: {
        top: number;
        right: number;
        bottom: number;
        left: number;
    };
    docView?: () => DocumentView | undefined;
}

@observer
export class TableBox extends React.Component<TableBoxProps> {
    // filters all data to just display selected data if brushed (created from an incoming link)
    @computed get _tableData() {
        if (this.incomingLinks.length! <= 0) return this.props.pairs;
        var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids);
        return this.props.pairs?.filter(pair => this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]));
    }

    @computed get incomingLinks() {
        return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
            .filter(link => {
                return link.link_anchor_1 == this.props.rootDoc.draggedFrom;
            }) // get links where this chart doc is the target of the link
            .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
    }

    @computed get columns() {
        if (!this.props.layoutDoc.dataViz_rowGuids) this.props.layoutDoc.dataViz_rowGuids = new List<string>();
        const guids = Cast(this.props.layoutDoc.dataViz_rowGuids, listSpec('string'), null);
        if (guids.length == 0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid()));
        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header != '' && header != undefined) : [];
    }

    // updates the 'selected' field to no longer include rows that aren't in the table
    filterSelectedRowsDown() {
        if (!this.props.layoutDoc.dataViz_selectedRows) this.props.layoutDoc.dataViz_selectedRows = new List<string>();
        const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null);
        const incomingSelected = this.incomingLinks.length ? StrListCast(this.incomingLinks[0].dataViz_selectedRows) : undefined;
        if (incomingSelected) {
            selected.map(guid => {
                if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1);
            }); // filters through selected to remove guids that were removed in the incoming data
        }
    }

    render() {
        this.filterSelectedRowsDown();
        if (this._tableData.length > 0) {
            return (
                <div className="table-container" style={{ height: this.props.height }}>
                    <table className="table">
                        <thead>
                            <tr className="table-row">
                                {this.columns
                                    .filter(col => !col.startsWith('select'))
                                    .map(col => {
                                        const header = React.createRef<HTMLElement>();
                                        return (
                                            <th
                                                key={this.columns.indexOf(col)}
                                                ref={header as any}
                                                style={{
                                                    color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined,
                                                    background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
                                                    fontWeight: 'bolder',
                                                    border: '3px solid black',
                                                }}
                                                onPointerDown={e => {
                                                    const downX = e.clientX;
                                                    const downY = e.clientY;
                                                    setupMoveUpEvents(
                                                        {},
                                                        e,
                                                        e => {
                                                            // dragging off a column to create a brushed DataVizBox
                                                            const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
                                                            const targetCreator = (annotationOn: Doc | undefined) => {
                                                                const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
                                                                embedding._dataViz = DataVizView.TABLE;
                                                                embedding._dataViz_axes = new List<string>([col, col]);
                                                                embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
                                                                embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
                                                                embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors);
                                                                embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor;
                                                                embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors);
                                                                return embedding;
                                                            };
                                                            if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
                                                                DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                                                                    dragComplete: e => {
                                                                        if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
                                                                            e.linkDocument.link_displayLine = true;
                                                                            e.linkDocument.link_matchEmbeddings = true;
                                                                            // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
                                                                            // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                                                                        }
                                                                    },
                                                                });
                                                                return true;
                                                            }
                                                            return false;
                                                        },
                                                        emptyFunction,
                                                        action(e => {
                                                            const newAxes = this.props.axes;
                                                            if (newAxes.includes(col)) {
                                                                newAxes.splice(newAxes.indexOf(col), 1);
                                                            } else if (newAxes.length > 1) {
                                                                newAxes[1] = col;
                                                            } else {
                                                                newAxes.push(col);
                                                            }
                                                            this.props.selectAxes(newAxes);
                                                        })
                                                    );
                                                }}>
                                                {col}
                                            </th>
                                        );
                                    })}
                            </tr>
                        </thead>
                        <tbody>
                            {this._tableData?.map((p, i) => {
                                var containsData = false;
                                var guid = StrListCast(this.props.layoutDoc.dataViz_rowGuids)![this.props.pairs.indexOf(p)];
                                this.columns.map(col => {
                                    if (p[col] != '' && p[col] != null && p[col] != undefined) containsData = true;
                                });
                                if (containsData) {
                                    return (
                                        <tr
                                            key={i}
                                            className="table-row"
                                            onClick={action(e => {
                                                // selecting a row
                                                const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null);
                                                if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1);
                                                else {
                                                    selected.push(guid);
                                                }
                                            })}
                                            style={{ background: StrListCast(this.props.layoutDoc.dataViz_selectedRows).includes(guid) ? 'lightgrey' : '', width: '110%' }}>
                                            {this.columns.map(col => {
                                                // each cell
                                                var colSelected = this.props.axes[0] == col || this.props.axes[1] == col;
                                                return (
                                                    <td key={this.columns.indexOf(col)} style={{ border: colSelected ? '3px solid black' : '1px solid black', fontWeight: colSelected ? 'bolder' : 'normal' }}>
                                                        {p[col]}
                                                    </td>
                                                );
                                            })}
                                        </tr>
                                    );
                                }
                            })}
                        </tbody>
                    </table>
                </div>
            );
        } else
            return (
                // when it is a brushed table and the incoming table doesn't have any rows selected
                <div className="chart-container">Selected rows of data from the incoming DataVizBox to display.</div>
            );
    }
}
