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';
import { generateUniqueID } from '../../tools/helpers';

const n = createNamespace('breadCrumbs');

const renderItem = ({ text, label, url, href, isDisplayAsString, isActive }, overrideIsDisplayAsString) => {
    const displayText = text || label;
    if (!displayText) {
        return null;
    }
    const linkUrl = url || href;
    if (overrideIsDisplayAsString || isDisplayAsString || !linkUrl) {
        return <span {...n('crumbText').withTestId().props}>{displayText}</span>;
    }
    const linkProps = {
        key: displayText,
        href: linkUrl
    };
    if (isActive) {
        linkProps['aria-current'] = 'page';
    }

    return (
        <Link {...n('crumbLink').props} {...linkProps}>
            {displayText}
        </Link>
    );
};

const getCrumbDisplay = crumbLevel => {
    let crumbDisplay;
    let key;
    if (crumbLevel.items) {
        crumbDisplay = (
            <ul {...n('linkList').props} aria-label={crumbLevel.label}>
                {crumbLevel.items.map((crumb, i) => (
                    <li key={generateUniqueID([crumb.text, crumb.label])}>
                        {i > 0 ? (
                            <span aria-hidden="true">{crumbLevel.glue || ', '}</span>
                        ) : ''}
                        {renderItem(crumb, crumbLevel.isDisplayAsString)}
                    </li>
                ))}
            </ul>
        );
        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} aria-hidden="true">{separator}</span>
    ) : (
        <span {...n('caretContainer').withTestId().props} aria-hidden="true"><Icon {...n('caret').withTestId().props} type="caretRight" /></span>
    )
);

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

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

const BreadCrumbs = ({
    crumbs,
    baseIconName,
    baseLinkUrl,
    baseLinkText,
    baseLinkAction,
    i18n
}) => {
    const i18nWithDefaults = { ...BreadCrumbs.defaultProps.i18n, ...i18n };

    let baseLinkNode;

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

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

    return (
        <nav {...n('container').withTestId().props} aria-label={i18nWithDefaults.label}>
            <ol {...n('linkList').props}>
                {baseLinkNode}
                {hasCrumbs && crumbs.map(renderGroup)}
            </ol>
        </nav>
    );
};

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

BreadCrumbs.propTypes = {
    baseLinkUrl: PropTypes.string,
    baseLinkText: PropTypes.string,
    baseIconName: PropTypes.string,
    baseLinkAction: PropTypes.func,
    crumbs: PropTypes.arrayOf(
        PropTypes.shape({
            ...crumbItemSchema,
            isDisplayAsString: PropTypes.bool,
            label: 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))
        })
    ),
    i18n: PropTypes.shape({
        label: PropTypes.string
    })
};

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

export default BreadCrumbs;
