import { Debug } from '@platform/ui.datagrid.debug';
import * as React from 'react';
import { Subject } from 'rxjs';
import { debounceTime, delay, filter, map, takeUntil } from 'rxjs/operators';
import { Button, color, COLORS, constants, coord, css, datagrid, Hr, log, util, } from '../common';
import { getFunc, SAMPLE } from '../SAMPLE';
import { TestGridView } from './Test.Grid.view';
export class TestGrid extends React.PureComponent {
    constructor() {
        var _a, _b, _c, _d;
        super(...arguments);
        this.state = {};
        this.unmounted$ = new Subject();
        this.state$ = new Subject();
        this.events$ = new Subject();
        this.grid = datagrid.Grid.create({
            totalColumns: 52,
            totalRows: 1000,
            getFunc,
            ns: ((_a = this.props.data) === null || _a === void 0 ? void 0 : _a.ns) || SAMPLE.ns,
            cells: ((_b = this.props.data) === null || _b === void 0 ? void 0 : _b.cells) || SAMPLE.cells,
            columns: ((_c = this.props.data) === null || _c === void 0 ? void 0 : _c.columns) || SAMPLE.columns,
            rows: ((_d = this.props.data) === null || _d === void 0 ? void 0 : _d.rows) || SAMPLE.rows,
        });
        this.getValueSync = (key) => {
            const cell = this.grid.data.cells[key];
            return cell && typeof cell.value === 'string' ? cell.value : undefined;
        };
        this.getValue = async (key) => this.getValueSync(key);
        this.refTable = coord.refs.table({
            getKeys: async () => Object.keys(this.grid.data.cells),
            getValue: this.getValue,
        });
        this.setLink = (key, uri, cellKey) => {
            cellKey = cellKey || this.lastSelection.cell || '';
            if (cellKey) {
                const cell = this.grid.data.cells[cellKey];
                const res = util.cell.value.cellData(cell).setLink(key, uri);
                this.grid.changeCells({ [cellKey]: res });
            }
        };
        this.postData = async () => {
        };
        this.button = (label, handler) => {
            return React.createElement(Button, { label: label, onClick: handler, block: true });
        };
        this.handleRefresh = (e) => {
            const { onRefresh } = this.props;
            if (onRefresh) {
                onRefresh(e);
            }
        };
    }
    componentDidMount() {
        const state$ = this.state$.pipe(takeUntil(this.unmounted$));
        state$.subscribe((e) => this.setState(e));
        const events$ = this.events$.pipe(takeUntil(this.unmounted$));
        events$
            .pipe(filter((e) => e.type === 'GRID/selection'), map((e) => e.payload))
            .subscribe((e) => {
            if (e.to.cell || !this.state.lastSelection) {
                this.state$.next({ lastSelection: e.to });
            }
        });
        events$
            .pipe(filter((e) => e.type === 'GRID/cells/change' ||
            e.type === 'GRID/rows/change' ||
            e.type === 'GRID/columns/change'), map((e) => e.payload), debounceTime(1500))
            .subscribe(async (e) => {
            console.log('🌼 POST (save)', e);
            const res = await this.postData();
            console.log('SAVED', res);
        });
        events$
            .pipe(filter((e) => e.type === 'GRID/cells/change'), map((e) => e.payload), delay(0))
            .subscribe(async (e) => {
            log.info('🐷 IGridCellsChanged', e);
            const wait = e.changes
                .filter((e) => e.isChanged)
                .map(async (change) => {
                const key = change.cell.key;
                const toValue = (data) => data && data.value ? data.value.toString() : undefined;
                const from = toValue(change.value.from);
                const to = toValue(change.value.to);
                await this.refTable.update({ key, from, to });
            });
            await Promise.all(wait);
        });
        events$
            .pipe(filter(() => true), filter((e) => e.type === 'GRID/EDITOR/end'), map((e) => e.payload))
            .subscribe(async (e) => {
            console.group('🌳 EDIT END');
            console.log('e', e);
            console.groupEnd();
        });
        const command$ = events$.pipe(filter((e) => e.type === 'GRID/command'), map((e) => e.payload));
        command$.subscribe((e) => {
            log.info('🐷 COMMAND:', e.command, e);
        });
        events$
            .pipe(filter((e) => e.type === 'GRID/clipboard'), map((e) => e.payload))
            .subscribe((e) => {
            log.info('📋 CLIPBOARD', e);
        });
        events$
            .pipe(filter((e) => e.type === 'GRID/clipboard/before/paste'), map((e) => e.payload))
            .subscribe((e) => {
            if (e.pending) {
                const cells = Object.assign(Object.assign({}, e.pending.cells), { A1: { value: 'boo' } });
                console.log('cells', cells);
            }
        });
        const gridEvents$ = this.grid.events$.pipe(takeUntil(this.unmounted$));
        gridEvents$.pipe(debounceTime(10)).subscribe(() => this.updateState());
        this.updateState();
    }
    componentWillUnmount() {
        this.unmounted$.next();
    }
    get lastSelection() {
        return this.state.lastSelection || { ranges: [] };
    }
    async updateState() {
        const { editorType } = this.props;
        const data = {
            debug: { editorType },
        };
        this.state$.next({ data });
        return data;
    }
    overlayFromCell(cell) {
        const data = this.grid.data.cells[cell || ''];
        const view = data && data.props ? util.toGridCellProps(data.props).view : {};
        const screen = view ? view.screen : undefined;
        if (data && screen && cell) {
            this.grid.command({
                command: 'OVERLAY/show',
                props: { screen, cell },
            });
        }
        else {
            this.grid.command({ command: 'OVERLAY/hide', props: {} });
        }
    }
    render() {
        const styles = {
            base: css({
                Absolute: 0,
                Flex: 'horizontal-stretch-stretch',
                backgroundColor: color.format(-0.08),
            }),
        };
        return (React.createElement("div", Object.assign({}, styles.base),
            this.props.left && this.renderLeft(),
            this.renderMain(),
            this.renderRight()));
    }
    renderLeft() {
        const styles = {
            base: css({
                Flex: 'vertical-start-start',
                position: 'relative',
                width: 230,
                padding: 10,
                Scroll: true,
                fontSize: 13,
                lineHeight: 1.6,
                borderRight: `solid 1px ${color.format(-0.1)}`,
            }),
        };
        return (React.createElement("div", Object.assign({}, styles.base),
            this.button('calc (all)', async () => {
                const cells = Object.keys(this.grid.data.cells);
                this.grid.calc.update({ cells });
            }),
            React.createElement(Hr, { margin: 5 }),
            this.button('redraw', () => this.grid.redraw()),
            this.button('focus', () => this.grid.focus()),
            this.button('updateHashes', () => {
                this.grid.updateHashes({ force: true });
                this.updateState();
            }),
            React.createElement(Hr, { margin: 5 }),
            this.button('changeCells', () => this.grid.changeCells({ A1: { value: 'hello' } })),
            this.button('changeCells (props)', () => this.grid.changeCells({ A1: { value: 'hello', props: { style: { bold: true } } } })),
            this.button('mergeCells (A5)', () => {
                this.grid.changeCells({
                    A5: { value: 'merged', props: { merge: { colspan: 3, rowspan: 5 } } },
                });
                this.grid.select({ cell: 'A5' });
            }),
            this.button('props.value (A1)', () => {
                this.grid.changeCells({
                    A1: { value: 'A1', props: { value: 'Display Value' } },
                });
            }),
            React.createElement(Hr, { margin: 5 }),
            this.button('columns (width) - A:200', () => this.grid.changeColumns({ A: { props: { grid: { width: 200 } } } })),
            this.button('columns (width) - A:300', () => this.grid.changeColumns({ A: { props: { grid: { width: 300 } } } })),
            this.button('rows (height) - 1:0', () => this.grid.changeRows({ '1': { props: { grid: { height: 0 } } } })),
            this.button('rows (height) - 1:120', () => this.grid.changeRows({ '1': { props: { grid: { height: 120 } } } })),
            React.createElement(Hr, { margin: 5 }),
            this.button('select: A1', () => this.grid.select({ cell: 'A1' })),
            this.button('select: A1 and range', () => this.grid.select({ cell: 'A1', ranges: ['B2:C4', 'C2:D7'] })),
            this.button('select: bottom/right', () => {
                this.grid.select({
                    cell: { row: this.grid.totalRows, column: this.grid.totalColumns },
                });
            }),
            this.button('select column: B:B', () => this.grid.select({ cell: 'B1', ranges: ['B:B'] })),
            this.button('select row: 3:3', () => this.grid.select({ cell: 'A3', ranges: ['3:3'] })),
            this.button('select row and column', () => this.grid.select({ cell: 'B1', ranges: ['3:3', 'B:B'], scrollToCell: false })),
            React.createElement(Hr, { margin: 5 }),
            this.button('scrollTo: A1', () => this.grid.scrollTo({ cell: 'A1' })),
            this.button('scrollTo: B5', () => this.grid.scrollTo({ cell: 'B5' })),
            this.button('scrollTo: bottom/right', () => {
                this.grid.scrollTo({
                    cell: { row: this.grid.totalRows, column: this.grid.totalColumns },
                });
            }),
            React.createElement(Hr, { margin: 5 }),
            this.button('screen: hide', () => {
                this.grid.command({ command: 'OVERLAY/hide', props: {} });
            }),
            this.button('screen: current selection', () => {
                const cell = this.lastSelection.cell;
                this.overlayFromCell(cell);
            }),
            this.button('screen: A1 (none defined)', () => this.overlayFromCell('A1')),
            this.button('screen: C1 (sample)', () => this.overlayFromCell('C1')),
            this.button('screen: C2 (child namespace)', () => this.overlayFromCell('C2')),
            React.createElement(Hr, { margin: 5 }),
            React.createElement(Label, null, "links"),
            this.button('main:"ns:abc"', () => this.setLink('main', 'ns:abc')),
            this.button('main:"ns:def"', () => this.setLink('main', 'ns:def')),
            this.button('main: undefined', () => this.setLink('main', undefined)),
            React.createElement(Hr, { margin: 5 }),
            React.createElement(Label, null, "http (localhost)"),
            this.button('post current data', () => this.postData())));
    }
    renderMain() {
        const styles = {
            base: css({ position: 'relative', flex: 1 }),
            inner: css({
                Absolute: 0,
            }),
            grid: css({ Absolute: 0 }),
        };
        return (React.createElement("div", Object.assign({}, styles.base),
            React.createElement("div", Object.assign({}, styles.inner),
                React.createElement(TestGridView, { style: styles.grid, grid: this.grid, editorType: this.props.editorType, "events$": this.events$ }))));
    }
    renderRight() {
        const data = this.state.data;
        if (!data) {
            return null;
        }
        const styles = {
            base: css({
                position: 'relative',
                backgroundColor: COLORS.DARK,
                color: COLORS.WHITE,
                width: 370,
                borderBottom: `solid 1px ${color.format(0.1)}`,
            }),
        };
        return (React.createElement("div", Object.assign({}, styles.base),
            React.createElement(Debug, { grid: this.grid, onRefresh: this.handleRefresh })));
    }
}
const Label = (props) => {
    const styles = {
        base: css({
            fontSize: 12,
            opacity: 0.4,
            marginBottom: 2,
            fontFamily: constants.MONOSPACE.FAMILY,
        }),
    };
    return (React.createElement("div", Object.assign({}, css(styles.base, props.style), { title: props.tooltip }), props.children));
};
