import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import 'bootstrap/dist/css/bootstrap.min.css';
import * as React from 'react';
import { Nav, Navbar, NavDropdown } from 'react-bootstrap';

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,
    /**
     * Additional Icon.
     */
    icon?: IconDefinition;
}

/**
 * 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;
    /**
     * Additional Icon.
     */
    icon?: IconDefinition;
}

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

export interface ToolbarState<D> extends ToolbarProps<D> {

}

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

    private _currentId = 0;

    constructor(props){
        super(props);
        this.state = Object.assign({
            bg: 'light',
            position: 'top',
            sticky: true
        },this.props);
    }

    _generateId(){
        const id = this._currentId;
        this._currentId += 1;
        return id;
    }

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

        const _this = this;

        switch (entry.type) {
            case 'action':
                if (entry.icon){
                    return (
                        <Nav.Link key={this._generateId()} onClick={e => {
                            entry.onClick(this.state.generateData());
                        }}><FontAwesomeIcon icon={entry.icon}/> {entry.label}</Nav.Link>
                    );
                }
                return (
                    <Nav.Link key={this._generateId()} onClick={e => {
                        entry.onClick(this.state.generateData());
                    }}>{entry.label}</Nav.Link>
                );
            case 'menu':
                return this._renderDropdown(entry);
            case 'link':
                if (entry.icon){
                    return (
                        <Nav.Link key={this._generateId()} href={entry.ref}>
                            <FontAwesomeIcon icon={entry.icon}/> {entry.label}
                        </Nav.Link>
                    );
                }
                return (
                    <Nav.Link key={this._generateId()} href={entry.ref}>{entry.label}</Nav.Link>
                );
        }

    }

    _renderDropdown(item: IMenu<D>) {
        // Issue: Drop-Down wont display the Dropdowns after opening a modal:
        // Issue: https://github.com/react-bootstrap/react-bootstrap/issues/5409
        // Dirty Fix: onClick={e => e.stopPropagation() in the "NavDropdown"
        return (
            <NavDropdown key={this._generateId()} id={item.id} title={item.label} onClick={e => e.stopPropagation()}>
                {/* Iterate over the deteced Modules. */}
                {item.items.map(entry => {
                    switch (entry.type) {
                        case 'action':
                            if (entry.icon){
                                return (
                                    <NavDropdown.Item key={this._generateId()} onClick={e => {
                                        entry.onClick(this.state.generateData());
                                    }}><FontAwesomeIcon icon={entry.icon} /> {entry.label}</NavDropdown.Item>
                                );
                            }
                            return (
                                <Nav.Link key={this._generateId()} onClick={e => {
                                    entry.onClick(this.state.generateData());
                                }}>{entry.label}</Nav.Link>
                            );
                        case 'divider':
                            return (
                                <NavDropdown.Divider key={this._generateId()} />
                            );
                        case 'link':
                            if (entry.icon){
                                return (
                                    <NavDropdown.Item key={this._generateId()} href={entry.ref}>
                                        <FontAwesomeIcon icon={entry.icon} /> {entry.label}
                                    </NavDropdown.Item>
                                );
                            }
                            return (
                                <NavDropdown.Item key={this._generateId()} href={entry.ref}>{entry.label}</NavDropdown.Item>
                            );
                        case 'menu':
                            return this._renderDropdown(entry);
                    }

                })}
            </NavDropdown>
        );
    }

    /**
     * Main Function to Render the Layout
     */
    render() {        
        this._currentId = 0;

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

export default Toolbar;