import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
import { CsvField } from '../../../../fields/URLField';
import { Docs } from '../../../documents/Documents';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { FieldViewProps, FieldView } from '../FieldView';
import { ChartBox } from './ChartBox';
import './DataVizBox.scss';
import { TableBox } from './components/TableBox';
import { PinProps } from '../trails';

enum DataVizView {
    TABLE = 'table',
    HISTOGRAM = 'histogram',
}

@observer
export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
    // says we have an object and any string
    // 2 ways of doing it
    // @observable private pairs: { [key: string]: number | string | undefined }[] = [];
    // @observable private pairs: { [key: string]: FieldResult }[] = [];
    @observable private pairs: { x: number; y: number }[] = [];
    private _chartBox: ChartBox | undefined;
    // // another way would be store a schema that defines the type of data we are expecting from an imported doc

    // method1() {
    //     this.pairs[0].x = 3;
    // }

    // method() {
    //     // this.pairs[0].x = 3;
    //     // go through the pairs
    //     const x = this.pairs[0].x;
    //     if (typeof x == 'number') {
    //         let x1 = Number(x);
    //         // let x1 = NumCast(x);
    //     }
    // }

    // could use field result
    // [key: string]: FieldResult;
    // instead of numeric x,y in there,

    // TODO: nda - make this use enum values instead
    // @observable private currView: DataVizView = DataVizView.TABLE;

    // TODO: nda - use onmousedown and onmouseup when dragging and changing height and width to update the height and width props only when dragging stops

    setChartBox = (chartBox: ChartBox) => {
        this._chartBox = chartBox;
    };

    @computed get currView() {
        return StrCast(this.rootDoc._dataVizView, 'table');
    }

    @action
    restoreView = (data: Doc) => {
        const changed = this.currView !== data.dataView && (this.rootDoc._dataVizView = data.dataView);
        const func = () => this._chartBox?.restoreView(data);
        if (changed) {
            setTimeout(func);
            return changed ? true : false;
        }
        return func() ?? false;
    };

    getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
        const anchor =
            this._chartBox?.getAnchor(pinProps) ??
            Docs.Create.TextanchorDocument({
                // when we clear selection -> we should have it so chartBox getAnchor returns undefined
                // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
                /*put in some options*/
            });

        anchor.dataView = this.currView;

        this.addDocument(anchor);
        return anchor;
    };
    constructor(props: any) {
        super(props);
        if (!this.rootDoc._dataVizView) {
            // TODO: nda - this might not always want to default to "table"
            this.rootDoc._dataVizView = 'table';
        }
    }

    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(DataVizBox, fieldKey);
    }

    @computed get selectView() {
        switch (this.currView) {
            case 'table':
                return <TableBox pairs={this.pairs} />;
            case 'histogram':
                return <ChartBox height={this.props.PanelHeight() - 32 /* height of 'change view' button */} getAnchor={this.getAnchor} setChartBox={this.setChartBox} rootDoc={this.rootDoc} pairs={this.pairs} dataDoc={this.dataDoc} />;
            // case "histogram":
            //     return (<HistogramBox rootDoc={this.rootDoc} pairs={this.pairs}/>)
        }
    }

    @computed get pairVals() {
        return fetch('/csvData?uri=' + this.dataUrl?.url.href).then(res => res.json());
    }

    @computed get dataUrl() {
        return Cast(this.dataDoc[this.fieldKey], CsvField);
    }

    componentDidMount() {
        this.props.setContentView?.(this);
        // this.createPairs();
        this.fetchData();
    }

    fetchData() {
        const uri = this.dataUrl?.url.href;
        fetch('/csvData?uri=' + uri).then(res =>
            res.json().then(
                action(res => {
                    this.pairs = res;
                })
            )
        );
    }

    // handle changing the view using a button
    @action changeViewHandler(e: React.MouseEvent<HTMLButtonElement>) {
        e.preventDefault();
        e.stopPropagation();
        this.rootDoc._dataVizView = this.currView === 'table' ? 'histogram' : 'table';
    }

    render() {
        if (this.pairs.length == 0) {
            return <div>Loading...</div>;
        }

        return (
            <div
                className="dataViz"
                onWheel={e => e.stopPropagation()}
                ref={r =>
                    r?.addEventListener(
                        'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
                        (e: WheelEvent) => {
                            if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
                            e.stopPropagation();
                        },
                        { passive: false }
                    )
                }>
                <button onClick={e => this.changeViewHandler(e)}>Change View</button>
                {this.selectView}
            </div>
        );
    }
}
