import React from 'react';
import PropTypes from 'prop-types';
import Icon from '../icon/Icon';
import Link from '../link/Link';
import { createNamespace } from '../../tools/namingTools';
import './styles/BreadCrumbs.scss';

const n = createNamespace('breadCrumbs');

const renderItem = ({ text, label, url, href, isDisplayAsString }, overrideIsDisplayAsString) => {
    const displayText = text || label;
    if (!displayText) {
        return null;
    }
    const linkUrl = url || href;
    if (overrideIsDisplayAsString || isDisplayAsString || !linkUrl) {
        return <span key={displayText} {...n('crumbText').withTestId().props}>{displayText}</span>;
    }
    return (
        <Link key={displayText} {...n('crumbLink').withTestId().props} href={linkUrl}>
            {displayText}
        </Link>
    );
};

const getCrumbDisplay = crumbLevel => {
    let crumbDisplay;
    let key;
    if (crumbLevel.items) {
        crumbDisplay = crumbLevel.items.map(crumb => renderItem(crumb, crumbLevel.isDisplayAsString));
        let i = 1;
        // insert glue between elements of the group
        while (i < crumbDisplay.length) {
            crumbDisplay.splice(i, 0, crumbLevel.glue || ', ');
            i += 2;
        }
        key = crumbLevel.items.map(item => item.text || item.label).join('-');
    } else {
        crumbDisplay = renderItem(crumbLevel);
        key = crumbLevel.text || crumbLevel.label;
    }
    return {
        crumbDisplay,
        key
    };
};

const getSeparator = separator => (
    separator ? (
        <span {...n('separatorContainer').withTestId().props}>{separator}</span>
    ) : (
        <span {...n('caretContainer').withTestId().props}><Icon {...n('caret').withTestId().props} type="caretRight" /></span>
    )
);

const renderGroup = crumbLevel => {
    const { crumbDisplay, key } = getCrumbDisplay(crumbLevel);

    if (!crumbDisplay) {
        return null;
    }
    return (
        <span key={key} {...n('crumbGroup').withTestId().props}>
            {getSeparator(crumbLevel.separator)}
            {crumbDisplay}
        </span>
    );
};

const BreadCrumbs = ({
    crumbs,
    baseIconName,
    baseLinkUrl,
    baseLinkText,
    baseLinkAction
}) => {
    let baseLinkNode;
    if (baseLinkUrl || baseLinkAction) {
        baseLinkNode = (
            <a {...n('baseLink').withTestId().props} href={baseLinkUrl} onClick={baseLinkAction}>
                {baseIconName ? <Icon {...n('icon').props} type={baseIconName} /> : baseLinkText}
            </a>
        );
    }
    const hasCrumbs = Boolean(crumbs && crumbs.length);

    if (!baseLinkNode && !hasCrumbs) {
        return null;
    }

    return (
        <div {...n('container').withTestId().props}>
            {baseLinkNode}
            {hasCrumbs && crumbs.map(renderGroup)}
        </div>
    );
};

const crumbItemSchema = {
    text: PropTypes.string,
    label: PropTypes.string,
    url: PropTypes.string,
    href: PropTypes.string
};

BreadCrumbs.propTypes = {
    baseLinkUrl: PropTypes.string,
    baseLinkText: PropTypes.string,
    baseIconName: PropTypes.string,
    baseLinkAction: PropTypes.func,
    crumbs: PropTypes.arrayOf(
        PropTypes.shape({
            ...crumbItemSchema,
            isDisplayAsString: PropTypes.string,
            separator: PropTypes.string, // what to add between this item and the previous one, defaults to right caret
            glue: PropTypes.string, // what to add between items of this crumb, if array
            // a crumb can be either a link in istelf, or a list of items that behave the same, and are joined by a ","
            items: PropTypes.arrayOf(PropTypes.shape(crumbItemSchema))
        })
    )
};

BreadCrumbs.defaultProps = {
    baseLinkUrl: null,
    baseLinkText: null,
    baseLinkAction: null,
    baseIconName: '',
    crumbs: null
};

export default BreadCrumbs;
