import * as React from 'react';
import { renderWithAdaptableContext } from '../../../View/renderWithAdaptableContext';
import { InternalAdaptableDateEditor, } from './InternalAdaptableDateEditor';
import { KeyCode } from 'ag-grid-enterprise';
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { DateFormatter } from '../../../Utilities/Helpers/FormatHelper';
function shouldClearExistingValue(params) {
    return params.eventKey === KeyCode.BACKSPACE || params.eventKey === KeyCode.DELETE;
}
function getStartValue(params) {
    return shouldClearExistingValue(params) ? '' : params.value;
}
const style = {
    position: 'absolute',
    top: '0px',
    left: '0px',
    right: '0px',
    bottom: '0px',
};
const defaultDateValueParser = ({ newValue, oldValue, defaultParser }) => {
    if ((typeof oldValue === 'string' || oldValue == null) && defaultParser) {
        return defaultParser(newValue);
    }
    return newValue;
};
export const AdaptableReactDateEditor = forwardRef((props, ref) => {
    const [initialValue] = useState(() => getStartValue(props));
    const valueRef = useRef(initialValue);
    const colValueParser = props.column.getColDef().valueParser;
    const valueParser = typeof colValueParser === 'function' ? colValueParser : defaultDateValueParser;
    const adaptable = props.context.__adaptable;
    const editorRef = useRef(null);
    useImperativeHandle(ref, () => {
        return {
            focusIn() {
                editorRef.current?.focus();
            },
            // the final value to send to the grid, on completion of editing
            getValue() {
                return valueRef.current;
            },
        };
    });
    const editorElement = (React.createElement(InternalAdaptableDateEditor, { defaultValue: initialValue, dateFormat: adaptable.adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat, onValueChange: (value) => {
            const invalid = isNaN(+value);
            if (valueParser) {
                const params = {
                    ...props,
                    oldValue: props.value,
                    newValue: value,
                    defaultParser: (value) => {
                        const Pattern = adaptable.adaptableOptions.userInterfaceOptions?.dateInputOptions?.dateFormat;
                        if (!Pattern) {
                            return value;
                        }
                        return DateFormatter(value, {
                            Pattern,
                        });
                    },
                };
                // @ts-ignore it will be fixed with https://github.com/AdaptableTools/adaptable/issues/2230
                valueRef.current = valueParser(params);
                props.onValueChange?.(valueRef.current);
            }
            else {
                valueRef.current = invalid ? null : value;
            }
            if (!invalid) {
                requestAnimationFrame(() => {
                    props.stopEditing();
                });
            }
        }, onStopEdit: (keyboardEventKey) => {
            if (keyboardEventKey === 'Escape') {
                props.api.stopEditing(true);
            }
            else {
                props.stopEditing();
            }
        }, ref: (editor) => {
            editorRef.current = editor;
            editor?.focus();
        } }));
    return React.createElement("div", { style: style }, renderWithAdaptableContext(editorElement, adaptable));
});
/**
 * Used by default for all `date` columns.
 *
 *
 * When the colDef has a `valueParser` provided as a function, it will be used before setting the value for the cell.
 * This is useful because dates can be stored as strings, numbers or Date instances - the value parser will be called with a `Date` instance,
 * and it's your responsibility to transform that to whatever format you want to use for persisting it to the grid.
 *
 * We strongly recommend you specify a `colDef.valueParser` function
 */
export class AdaptableDateEditor {
    value;
    el;
    params;
    editor;
    unmountReactRoot;
    valueParser = defaultDateValueParser;
    init(params) {
        this.value = getStartValue(params);
        const { valueParser } = params.column.getColDef();
        this.params = params;
        if (typeof valueParser === 'function') {
            this.valueParser = valueParser;
        }
        this.el = document.createElement('div');
        Object.keys(style).forEach((key) => {
            //@ts-ignore
            this.el.style[key] = style[key];
        });
    }
    /* Component Editor Lifecycle methods */
    // gets called once when grid ready to insert the element
    getGui() {
        return this.el;
    }
    // the final value to send to the grid, on completion of editing
    getValue() {
        return this.value;
    }
    focusIn() {
        this.editor?.focus();
    }
    focusOut() { }
    getAdaptableInstance(params) {
        const adaptable = params.context.__adaptable;
        return adaptable;
    }
    // after this component has been created and inserted into the grid
    afterGuiAttached() {
        const adaptable = this.getAdaptableInstance(this.params);
        const defaultValue = shouldClearExistingValue(this.params) ? '' : this.params.value;
        const editorElement = (React.createElement(InternalAdaptableDateEditor, { defaultValue: defaultValue, dateFormat: adaptable.adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat, onValueChange: (value) => {
                const invalid = isNaN(+value);
                if (this.valueParser) {
                    const params = {
                        ...this.params,
                        oldValue: this.params.value,
                        newValue: value,
                        defaultParser: (value) => {
                            const Pattern = adaptable.adaptableOptions.userInterfaceOptions?.dateInputOptions?.dateFormat;
                            if (!Pattern) {
                                return value;
                            }
                            return DateFormatter(value, {
                                Pattern,
                            });
                        },
                    };
                    // @ts-ignore it will be fixed with https://github.com/AdaptableTools/adaptable/issues/2230
                    this.value = this.valueParser(params);
                }
                else {
                    this.value = invalid ? null : value;
                }
                if (!invalid) {
                    requestAnimationFrame(() => {
                        this.params.stopEditing();
                    });
                }
            }, onStopEdit: (keyboardEventKey) => {
                if (keyboardEventKey === 'Escape') {
                    this.params.api.stopEditing(true);
                }
                else {
                    this.params.stopEditing();
                }
            }, ref: (editor) => {
                this.editor = editor;
                editor?.focus();
            } }));
        this.unmountReactRoot = adaptable.renderReactRoot(renderWithAdaptableContext(editorElement, adaptable), this.el);
    }
    destroy() {
        this.unmountReactRoot?.();
    }
}
