import { assignIn } from 'lodash';
import * as React from 'react';
import { Nav, Navbar, NavDropdown } from 'react-bootstrap';
import { generateId } from '../../../lib/helpers/idMethods';

export interface ToolbarProps<D> {
    toolbar: IToolbar<D>;
    generateData(): D;
    position?: 'top' | 'bottom',
    sticky?: boolean;
    bg?: 'light' | 'dark',
    brand?: ILink
}

/**
 * Definition of a Toolbar.
 *
 * @export
 * @interface IToolbar
 * @template D
 */
export interface IToolbar<D> {
    /**
     * Items of the toolbar.
     *
     * @type {(Array<IAction<D> | IMenu<D> | ILink>)}
     * @memberof IToolbar
     */
    items: Array<IAction<D> | IMenu<D> | ILink>
}

export interface IAction<D> {
    type: 'action';
    /**
     * Action which should be performed if the element
     * has been clicked.
     *
     * @param {D} data
     * @memberof IAction
     */
    onClick(data: D): void;
    /**
     * Label of the Menu.
     *
     * @type {string}
     * @memberof IAction
     */
    label: string,
}

/**
 * A Menu of the Toolbar
 *
 * @export
 * @interface IMenu
 * @template D
 */
export interface IMenu<D> {
    type: 'menu',
    /**
     * The Menu ID.
     *
     * @type {string}
     * @memberof IMenu
     */
    id: string;
    /**
     * Label of the Menu
     *
     * @type {string}
     * @memberof IMenu
     */
    label: string,
    /**
     * Items of the Menu.
     *
     * @type {(Array<IAction<D> | ILink | IDivider>)}
     * @memberof IMenu
     */
    items: Array<IAction<D> | IMenu<D> | ILink | IDivider>;
}

/**
 * A Classical Link.
 *
 * @export
 * @interface ILink
 */
export interface ILink {
    /**
     * Type of the Element.
     *
     * @type {'link'}
     * @memberof ILink
     */
    type: 'link';
    /**
     * Label
     *
     * @type {string}
     * @memberof ILink
     */
    label: string;
    /**
     * Referene, where the client should be navigated on click
     *
     * @type {string}
     * @memberof ILink
     */
    ref: string;
}

/**
 * A Divider in a Menu.
 *
 * @export
 * @interface IDivider
 */
export interface IDivider {
    /**
     * Type Element
     *
     * @type {'divider'}
     * @memberof IDivider
     */
    type: 'divider'
}

export interface ToolbarState {

}

class Toolbar<D> extends React.Component<ToolbarProps<D>, ToolbarState> {

    _renderMenuEntry(item: IAction<D> | IMenu<D> | ILink) {

        const _this = this;

        switch (item.type) {
            case 'action':
                return (
                    <Nav.Link key={generateId()} onClick={e => {
                        item.onClick(this.props.generateData());
                    }}>{item.label}</Nav.Link>
                );
            case 'menu':
                return this._renderDropdown(item);
            case 'link':
                return (
                    <Nav.Link key={generateId()} href={item.ref}>{item.label}</Nav.Link>
                );
        }

    }

    _renderDropdown(item: IMenu<D>) {
        return (
            <NavDropdown key={generateId()} id={item.id} title={item.label}>
                {/* Iterate over the deteced Modules. */}
                {item.items.map(entry => {
                    switch (entry.type) {
                        case 'action':
                            return (
                                <NavDropdown.Item key={generateId()} onClick={e => {
                                    entry.onClick(this.props.generateData());
                                }}>{entry.label}</NavDropdown.Item>
                            );
                        case 'divider':
                            return (
                                <NavDropdown.Divider key={generateId()} />
                            );
                        case 'link':
                            return (
                                <NavDropdown.Item key={generateId()} href={entry.ref}>{entry.label}</NavDropdown.Item>
                            );
                        case 'menu':
                            return this._renderDropdown(entry);
                    }

                })}
            </NavDropdown>
        );
    }

    /**
     * Main Function to Render the Layout
     */
    render() {
        const defaultOptions: Partial<ToolbarProps<D>> = {
            bg: 'dark',
            position: 'top',
            sticky: true
        }

        const opts: ToolbarProps<D> = assignIn(defaultOptions, this.props);

        return (
            <>
                {opts.sticky ?
                    // Render a collapsable Navbar containing the defined Menu structure. 
                    <Navbar collapseOnSelect sticky={opts.position} expand="lg" bg={opts.bg} variant={opts.bg}>
                        {opts.brand ? <>
                            <Navbar.Brand href={opts.brand.ref}>{opts.brand.label}</Navbar.Brand>
                            <Navbar.Toggle aria-controls="responsive-navbar-nav" />
                        </> :
                            <Navbar.Toggle aria-controls="responsive-navbar-nav" />
                        }
                        <Navbar.Collapse id="responsive-navbar-nav">
                            {opts.toolbar.items.map(item => this._renderMenuEntry(item))}
                        </Navbar.Collapse>
                    </Navbar> :
                    <Navbar collapseOnSelect fixed={opts.position} expand="lg" variant={opts.bg}>
                        {opts.brand ? <>
                            <Navbar.Brand href={opts.brand.ref}>{opts.brand.label}</Navbar.Brand>
                            <Navbar.Toggle aria-controls="responsive-navbar-nav" />
                        </> :
                            <Navbar.Toggle aria-controls="responsive-navbar-nav" />
                        }
                        <Navbar.Collapse id="responsive-navbar-nav">
                            {opts.toolbar.items.map(item => this._renderMenuEntry(item))}
                        </Navbar.Collapse>
                    </Navbar>
                }
            </>
        );
    }
}

export default Toolbar;