import classNames from "classnames";
import * as React from "react";
import * as Classes from "../../common/classes";
import { Elevation } from "../../common/elevation";
import { DISPLAYNAME_PREFIX, HTMLDivProps, IProps } from "../../common/props";

import { Tab, TabId } from "./Tab";

export interface ITabsProps extends IProps {
    /**
     * Controls the intensity of the drop shadow beneath the tab: the higher
     * the elevation, the higher the drop shadow. At elevation `0`, no drop
     * shadow is applied.
     *
     * @default 0
     */
    elevation?: Elevation;

    /**
     * Whether the tab should respond to user interactions. If set to `true`,
     * hovering over the tab will increase the tab's elevation
     * and change the mouse cursor to a pointer.
     *
     * @default false
     */
    interactive?: boolean;

    /**
     * Header props
     */
    additionalHeaderProps?: IProps & HTMLDivProps;

    /**
     * Additional Header element
     */
    additionalHeader?: React.ReactNode;

    /**
     * Header element
     */
    children?: Tab[] | React.ReactNode;

    /**
     * Header element
     */
    selectedTabId?: TabId;

    /**
     * A callback function that is invoked when a tab in the tab list is clicked.
     */
    onChange?(newTabId: TabId, prevTabId: TabId, event: React.MouseEvent<HTMLElement>): void;
}

export class Tabs extends React.PureComponent<ITabsProps & HTMLDivProps, {}> {
    public static displayName = `${DISPLAYNAME_PREFIX}.Tabs`;
    public static defaultProps: ITabsProps = {
        elevation: Elevation.ZERO,
        interactive: false,
    };

    state: {
        activeItemId: TabId
    } = {
        activeItemId: undefined
    }

    public componentWillReceiveProps({ selectedTabId }: ITabsProps) {
        if (selectedTabId !== undefined) {
            // keep state in sync with controlled prop, so state is canonical source of truth
            this.setState({ activeItemId: selectedTabId });
        }
    }

    private isTabActive(item: Tab, index: number): boolean {
        return this.state.activeItemId === undefined && index === 0
        ? true
        : item.props.id === this.state.activeItemId
    }

    private renderHeaders() {
        return (this.props.children as Tab[]).map((item, index) => {
            const { className: headerClassName, ...htmHeaderProps } = item.props.headerProps || {
                className: null
            };

            const activeClass: string = this.isTabActive(item, index) && Classes.TAB_HEADER_ACTIVE;
            const disabledClass: string = item.props.disabled && Classes.TAB_HEADER_DISABLED;

            const classesHeader = classNames(
                Classes.TAB_HEADER,
                activeClass,
                disabledClass,
                "col-auto",
                headerClassName
            );

            return <div key={item.props.id} className={classesHeader} {...htmHeaderProps} onClick={(e) => {
                if (!item.props.disabled && item.props.id !== this.state.activeItemId) {
                    if (this.props.onChange) this.props.onChange(item.props.id, this.state.activeItemId, e);
                    this.setState({activeItemId: item.props.id});
                }
            }}>
                {item.props.title}
            </div>
        })
    }

    public render() {
        const { className, elevation, interactive, children, additionalHeader, additionalHeaderProps, onChange, ...htmlProps } = this.props;
        const { className: additionalHeaderClassName, ...htmHeaderProps } = additionalHeaderProps || {
            className: null
        };
        
        const classes = classNames(
            Classes.TABS,
            { [Classes.INTERACTIVE]: interactive },
            Classes.elevationClass(elevation),
            className,
        );

        const classesHeader = classNames(
            Classes.TABS_HEADER,
            "align-items-stretch",
            "row"
        );

        const classesAdditionalHeader = classNames(
            "col",
            additionalHeaderClassName,
        );

        return (
            <div className={classes} {...htmlProps}>
                <div className={classesHeader}>
                    {this.renderHeaders()}
                    {additionalHeader && <div className={classesAdditionalHeader} {...htmHeaderProps}>{additionalHeader}</div>}
                </div>
                {(children as Tab[]).filter((item, index) => this.isTabActive(item, index)).map(i => React.cloneElement(i as any, {key: i.props.id}))}
            </div>
        );
    }
}
