import * as React from 'react';

export default {
    title: 'Components/Grid',
};


type FilterString<S extends string, T extends string> = S extends T ? never : S;
type Split<S extends string, D extends string> = string extends S
    ? string[]
    : S extends ''
    ? []
    : S extends `${infer T}${D}${infer U}`
    ? [T, ...Split<U, D>]
    : [S];

function useGridTemplate<T extends string>(template: T) {
    type SplitLines = Split<T, '\n'>[number];
    type WithoutFourSpace = Split<SplitLines, '    '>[number];
    type WithoutTripleSpace = Split<WithoutFourSpace, '   '>[number];
    type WithoutDoubleSpace = Split<WithoutTripleSpace, '  '>[number];
    type SplitTokens = Split<WithoutDoubleSpace, ' '>[number];
    type AreaName = FilterString<SplitTokens, ''>;

    const RootComponentRef = React.useRef(
        ({
            style,
            columns,
            rows,
            ...props
        }: React.ComponentProps<'div'> & {
            columns?: React.CSSProperties['gridTemplateColumns'];
            rows?: React.CSSProperties['gridTemplateRows'];
        }) => {
            return (
                <div
                    {...props}
                    style={{
                        ...style,
                        display: 'grid',
                        gridTemplateColumns: columns,
                        gridTemplateRows: rows,
                        gridTemplateAreas: template
                            .trim()
                            .split('\n')
                            .map((area) => `"${area}"`)
                            .join('\n'),
                    }}
                />
            );
        },
    );
    const ItemComponentRef = React.useRef(
        React.forwardRef(function ItemComponentRef(
            { style, area, ...props }: { area: AreaName } & React.ComponentProps<'div'>,
            ref?: React.Ref<HTMLDivElement>,
        ) {
            return <div ref={ref} {...props} style={{ ...style, gridArea: area }} />;
        }),
    );
    const Resizer = React.useRef(
        ({
            style,
            area,
            onResize,
            dimension,
            onResizeFinished,
            ...props
        }: {
            area: AreaName;
            dimension: 'horizontal' | 'vertical';
            onResize: (amount: number) => void;
            onResizeFinished?: () => void;
        } & React.ComponentProps<'div'>) => {
            return (
                // eslint-disable-next-line jsx-a11y/no-static-element-interactions
                <div
                    {...props}
                    style={{ ...style, gridArea: area }}
                    onMouseDown={function onMouseDown() {
                        function onMouseMove(e: MouseEvent) {
                            onResize(dimension === 'horizontal' ? e.movementX : e.movementY);
                        }

                        function onMouseUp() {
                            document.removeEventListener('mousemove', onMouseMove);
                            onResizeFinished?.();
                        }

                        document.addEventListener('mouseup', onMouseUp, { once: true });
                        document.addEventListener('mousemove', onMouseMove);
                    }}
                />
            );
        },
    );

    return {
        Root: RootComponentRef.current,
        Item: ItemComponentRef.current,
        Resizer: Resizer.current,
    };
}

export const DescriptUI = () => {
    const scriptRef = React.useRef<HTMLDivElement>(null);
    const timelineRef = React.useRef<HTMLDivElement>(null);
    const [scriptSize, scriptSizeSet] = React.useState(700);
    const [timelineSize, timelineSizeSet] = React.useState(200);
    const Grid = useGridTemplate(`
      header           header         header         header
      script           scriptResize   video          properties
      timelineResize   timelineResize timelineResize timelineResize
      timeline         timeline       timeline       timeline
    `);

    return (
        <Grid.Root
            columns={`minmax(400px, ${scriptSize}px) 10px minmax(350px, 1fr) 254px`}
            rows={`50px minmax(400px, 1fr) 10px minmax(150px, ${timelineSize}px)`}
            style={{ height: 'calc(100vh - 30px)', width: '100vw' }}
        >
            <Grid.Item area="header" style={{ background: 'yellow' }}>
                Header
            </Grid.Item>
            <Grid.Item ref={scriptRef} area="script" style={{ background: 'red' }}>
                Script
            </Grid.Item>
            <Grid.Resizer
                area="scriptResize"
                dimension="horizontal"
                style={{ background: 'grey', cursor: 'ew-resize' }}
                onResize={(amount) => {
                    scriptSizeSet((s) => s + amount);
                }}
                onResizeFinished={() => {
                    if (!scriptRef.current) {
                        return;
                    }

                    scriptSizeSet(scriptRef.current.clientWidth);
                }}
            />
            <Grid.Item area="video" style={{ background: 'lightblue' }}>
                Video
            </Grid.Item>
            <Grid.Item area="properties" style={{ background: 'green' }}>
                Properties
            </Grid.Item>
            <Grid.Resizer
                area="timelineResize"
                dimension="vertical"
                style={{ background: 'grey', cursor: 'ns-resize' }}
                onResize={(amount) => {
                    timelineSizeSet((s) => s - amount);
                }}
                onResizeFinished={() => {
                    if (!timelineRef.current) {
                        return;
                    }

                    timelineSizeSet(timelineRef.current.clientHeight);
                }}
            />
            <Grid.Item ref={timelineRef} area="timeline" style={{ background: 'pink' }}>
                Timeline
            </Grid.Item>
        </Grid.Root>
    );
};
