import { componentsById } from '../componentManagement';
import { ComponentId } from '../dataModels';
import { ComponentBase, ComponentState } from './componentBase';

export type FlowState = ComponentState & {
    _type_: 'FlowContainer-builtin';
    children?: ComponentId[];
    row_spacing?: number;
    column_spacing?: number;
    justify?: 'left' | 'center' | 'right' | 'justify' | 'grow';
};

export class FlowComponent extends ComponentBase {
    state: Required<FlowState>;

    private innerElement: HTMLElement;

    createElement(): HTMLElement {
        let element = document.createElement('div');
        element.classList.add('rio-flow-container');

        this.innerElement = document.createElement('div');
        this.innerElement.classList.add('rio-flow-inner');
        element.appendChild(this.innerElement);

        return element;
    }

    updateElement(
        deltaState: FlowState,
        latentComponents: Set<ComponentBase>
    ): void {
        super.updateElement(deltaState, latentComponents);

        if (deltaState.row_spacing !== undefined) {
            this.innerElement.style.rowGap = `${deltaState.row_spacing}rem`;
        }

        if (deltaState.column_spacing !== undefined) {
            this.innerElement.style.columnGap = `${deltaState.column_spacing}rem`;
        }

        if (deltaState.justify !== undefined) {
            this.innerElement.style.justifyContent = {
                left: 'start',
                right: 'end',
                center: 'center',
                justify: 'space-between',
                grow: 'stretch',
            }[deltaState.justify];
        }

        if (deltaState.children !== undefined) {
            this.replaceChildren(
                latentComponents,
                deltaState.children,
                this.innerElement,
                true
            );
            this.updateChildGrows(
                deltaState.children,
                deltaState.justify ?? this.state.justify
            );
        }
    }

    onChildGrowChanged(): void {
        this.updateChildGrows(this.state.children, this.state.justify);
    }

    private updateChildGrows(children: ComponentId[], justify: string): void {
        // Set the children's `flex-grow`
        let hasGrowers = false;
        for (let [index, childId] of children.entries()) {
            let childComponent = componentsById[childId]!;
            let childWrapper = this.innerElement.children[index] as HTMLElement;

            if (childComponent.state._grow_[0]) {
                hasGrowers = true;
                childWrapper.style.flexGrow = '1';
            } else {
                childWrapper.style.flexGrow = '0';
            }
        }

        // If nobody wants to grow, all of them do
        if (justify === 'grow' && !hasGrowers) {
            for (let childWrapper of this.innerElement.children) {
                (childWrapper as HTMLElement).style.flexGrow = '1';
            }
        }
    }
}
