import React, { useState, useEffect, useLayoutEffect, useMemo } from 'react';
import { getColumns, getRowHeights, getRow } from './tools';

const defaultHeights = {
    children: {},
    main: [],
    columns: 0
};

// when we get the height of each row, we need to know on wat row is each item in order to know its desired height
const inflateItemHeights = (rowHeights, columns, nItems) => {
    const heights = [];
    for (let i = 0; i < nItems; i += 1) {
        const rowIndex = getRow(i, columns);
        heights[i] = rowHeights[rowIndex];
    }
    return heights;
};

/**
 * custom hook that calculates element heights among the sibling elements on the same row in a layout
 * so that an element has information about the highest height of its sibilngs, and of some of their children, and
 * that it is then possible to vertically align elements and their contents in a row
 * @param {number} nItems the number of items in the whole layout
 * @param {array} childrenRefNames strings of the refs names we need to also calculate among children of the items
 */
export const useRowHeights = (nItems, childrenRefNames = null) => {
    const { mainRefs, childrenRefs } = useMemo(() => {
        const refs = { childrenRefs: {}, mainRefs: [] };
        for (let index = 0; index < nItems; index += 1) {
            refs.mainRefs[index] = React.createRef();
            if (childrenRefNames) {
                childrenRefNames.forEach(name => {
                    refs.childrenRefs[name] = refs.childrenRefs[name] || [];
                    refs.childrenRefs[name][index] = React.createRef();
                });
            }
        }
        return refs;
    }, [nItems, childrenRefNames]);

    const [heights, setHeights] = useState(defaultHeights);
    useLayoutEffect(() => {
        const columns = getColumns(mainRefs);
        // pointless to do all the calculations if we have one element per row
        if (columns <= 1) { return; }

        // first render, compute children only, as the result will trigger a rerender that'll influence item heights
        if (heights.columns !== columns) {
            const childrenHeights = {};
            if (childrenRefNames) {
                childrenRefNames.forEach(name => {
                    childrenHeights[name] = inflateItemHeights(
                        getRowHeights(childrenRefs[name], columns),
                        columns,
                        nItems
                    );
                });
            }
            setHeights({
                ...defaultHeights,
                columns,
                children: childrenHeights
            });
        } else if (!heights.main.length) {
            const mainRowHeights = inflateItemHeights(
                getRowHeights(mainRefs, columns),
                columns,
                nItems
            );
            setHeights({
                ...heights,
                main: mainRowHeights
            });
        }
    });

    useEffect(() => {
        let timeout;
        const handleResize = () => {
            clearTimeout(timeout);
            setHeights(defaultHeights);
        };
        const debounceResize = () => {
            if (timeout) { clearTimeout(timeout); }
            timeout = setTimeout(handleResize, 250);
        };
        window.addEventListener('resize', debounceResize);
        return () => {
            if (timeout) { clearTimeout(timeout); }
            window.removeEventListener('resize', debounceResize);
        };
    }, []);

    return [mainRefs, childrenRefs, heights];
};
