import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';

import './NumberCellEditor.scss';

/**
 *
 * Composant d'édition d'un nombre dans une cellule d'AG Grid.
 *
 * @component
 * @param {number} props.value - Valeur initiale
 * @param {number} props.min - Valeur min
 * @param {number} props.max - Valeur max
 * @param {number} props.step - Pas de l'incrément
 * @param {string} props.className - Classe CSS à appliquer
 * @param {boolean} props.nullable - Indique si l'absence de valeur est valide. défaut : une valeur vide n'est pas valide
 * @param {string} props.placeholder - Texte d'exemple
 */
// TODO composant à refactoriser via un AbstractCellEditor (à la manière de AbstractPopinEditor) ?
const NumberCellEditor = forwardRef((props, ref) => {
    const [value, setValue] = useState(Number.parseInt(props.value, 10));
    const refInput = useRef(null);

    useEffect(() => {
        // focus on the input
        setTimeout(() => refInput.current.focus());
    }, []);

    /* Component Editor Lifecycle methods */
    useImperativeHandle(ref, () => ({
        // the final value to send to the grid, on completion of editing
        getValue() {
            // n'arrive que si props.nullable
            if ((value ?? '') === '' || Number.isNaN(value)) {
                return null;
            }

            let floatValue = parseFloat(value);

            if (typeof props.step != 'undefined' && props.step !== null && Number.isInteger(props.step) && !Number.isInteger(floatValue)) {
                floatValue = Math.floor(floatValue);
            }

            if (typeof props.min != 'undefined' && props.min !== null && value < props.min) {
                floatValue = Math.max(props.min, floatValue);
            }

            if (typeof props.max != 'undefined' && props.max !== null && value > props.max) {
                floatValue = Math.min(props.max, floatValue);
            }

            return isNaN(floatValue) ? props.min || 0 : floatValue;
        },

        // Gets called once before editing starts, to give editor a chance to
        // cancel the editing before it even starts.
        isCancelBeforeStart() {
            return false;
        },

        // Gets called once when editing is finished (eg if Enter is pressed).
        // If you return true, then the result of the edit will be ignored.
        isCancelAfterEnd: () => !props.nullable && ((value ?? '') === '' || Number.isNaN(value))
    }));

    return (
        <input
            className={'NumberCellEditor ' + (props.className ?? '')}
            type="number"
            ref={refInput}
            value={value}
            onChange={(event) => setValue(event.target.value)}
            min={props.min ?? ''}
            max={props.max ?? ''}
            step={props.step ?? ''}
            placeholder={props.placeholder ?? ''}
        />
    );
});

NumberCellEditor.displayName = 'NumberCellEditor';

export default NumberCellEditor;
