import React, { useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import { useForm } from 'react-hook-form';
import { createNamespace } from '../../tools/namingTools';
import { CTA_BUY, CTA_BUY_MORE, CTA_DOMAIN_ADD_TO_CART, CTA_NO_ACTION } from '../../constants/actions';
import { domainAppDataShape } from '../../constants/components/prop-types/domain-app';
import { ADD_ACTION, REMOVE_ACTION, SELECTED_ACTION } from '../../constants/components/domain-app';
import { useResponsive } from '../../tools/widths/useResponsive';
import { replacePlaceholders } from '../../tools/stringTools';
import { getDomainActionLabel } from '../../tools/components/domainApp';
import { useDomainSuggestions } from '../../tools/ajax/useDomainSuggestions';
import { domainAppDataStore } from '../../store/domainApp';
import { i18nMock as i18nDomainsMock } from '../../../mocks/application/domains/i18n';

import Preloader from '../../atoms/preloader/Preloader';
import ButtonIcon from '../../atoms/button-icon/ButtonIcon';
import InputSearch from '../../atoms/input-search/InputSearch';

import './styles/DomainApp.scss';

import withListener from '../withListener';

const n = createNamespace('DomainApp');

const renderTableName = name => (
    <span {...n('name').props}>{name}</span>
);

const renderTablePrice = (price, frequency) => {
    if (!price) {
        return '';
    }

    return (
        <span {...n('price').props}>
            <span {...n('srOnly').props}>{`${price} / ${frequency}`}</span>
            <span aria-hidden="true">
                <strong>{price}</strong>
                {` / ${frequency}`}
            </span>
        </span>
    );
};

const renderTableAction = (label, icon, theme, isDisabled, clickCallback = () => {}, name, ariaLabel) => (
    <span {...n('action').withTestId(name).props}>
        <ButtonIcon
            {...n('actionButton', icon).props}
            icon={icon}
            iconClass={n('actionIcon', icon).props.className}
            theme={theme}
            onClick={clickCallback}
            disabled={isDisabled}
            aria-label={ariaLabel}
        >
            {label}
        </ButtonIcon>
    </span>
);

export const DomainAppComponent = ({
    data: {
        application,
        config
    },
    fetchSuggestions
}) => {
    const appId = application?.config?.id;
    const canRouteToV2 = config?.canRouteToV2;
    const isAddToCartCTAEnabled = config?.channelSettings?.isAddToCartCTAEnabled;
    let hasCallToActions = true;

    // if there is a call to action in the list that specifies that there are
    // no actions, we should disable the add to cart
    if (application.callToActions && application.callToActions.items) {
        const noActionCta = application.callToActions.items.find(item => item.actionType === CTA_NO_ACTION);
        if (noActionCta) {
            hasCallToActions = false;
        }
    }
    const { i18n } = application.domains;
    const { smallDown, largeDown } = useResponsive();
    const { handleSubmit, register } = useForm();
    const { suggestions, setSearchValue, isLoading } = useDomainSuggestions(application.domains, fetchSuggestions);

    const onSubmit = formData => {
        setSearchValue(formData.domain);
    };

    const {
        selectedDomains,
        addDomain,
        removeDomain,
        initializeDomains,
        setCallToActions,
        handleBuyNowDomains,
        handleAddToCartDomains,
        callToActions
    } = domainAppDataStore();

    useEffect(() => {
        initializeDomains(appId);
    }, [appId, initializeDomains]);

    const getCheckoutUrl = useCallback(() => {
        const isLoggedIn = config.user && config.user.isLoggedIn;
        const { checkoutUrl, loginUrl } = application.domains;
        return isLoggedIn ? checkoutUrl : loginUrl + checkoutUrl;
    }, [config.user, application.domains]);

    const hasDomains = selectedDomains && selectedDomains.length > 0;
    useEffect(() => {
        if (!hasCallToActions) {
            setCallToActions([]);
            return;
        }
        if (canRouteToV2) {
            const addToCartCTA = [
                isAddToCartCTAEnabled && {
                    label: i18n.addToCart,
                    disabled: !hasDomains,
                    actionType: CTA_DOMAIN_ADD_TO_CART,
                    theme: 'emphasisAlt',
                    icon: 'cart',
                    name: 'addToCartButton'
                }
            ];

            const buyableCTAResponse = application.callToActions.items.filter(
                item => item.actionType === CTA_BUY || item.actionType === CTA_BUY_MORE
            );

            const buyableCTA = [];
            if (buyableCTAResponse.length) {
                buyableCTA.push({
                    label: i18n.buyNow,
                    disabled: !hasDomains,
                    actionType: buyableCTAResponse[0].actionType,
                    theme: 'emphasis',
                    name: 'buyNowButton'
                });
            }

            setCallToActions([
                ...addToCartCTA,
                ...buyableCTA
            ].filter(cta => cta));
        } else {
            setCallToActions([
                {
                    label: i18n.checkout,
                    disabled: !hasDomains,
                    theme: 'primary',
                    icon: 'cart',
                    url: getCheckoutUrl(),
                    name: 'checkoutButton'
                }
            ]);
        }
    }, [
        canRouteToV2,
        hasDomains,
        setCallToActions,
        i18n, getCheckoutUrl,
        hasCallToActions,
        isAddToCartCTAEnabled,
        application.callToActions.items
    ]);

    const defaultSearchValue = '';

    const hasDomainSuggestions = Boolean(suggestions && suggestions.length);
    const hasSelectedNames = Boolean(selectedDomains && selectedDomains.length);
    // on mobile devices, the call to actions are in the tabs menu only.
    const hasFooterCallToActions = !largeDown;

    const renderTableRow = (item, action) => {
        const { name, formattedPricePerYear } = item;
        const { removeLabel, selectedLabel, selectLabel } = getDomainActionLabel(name, i18n);
        const isAddState = action === ADD_ACTION;
        const isRemoveState = action === REMOVE_ACTION;
        const isSelectedState = action === SELECTED_ACTION;

        // Set Button label based on the row action
        const defaultButtonLabel = isRemoveState ? i18n.remove : i18n.select;
        const buttonLabel = isSelectedState ? i18n.selected : defaultButtonLabel;

        // Set Button icon based on the row action
        const buttonIcon = isSelectedState ? 'check' : null;
        let buttonStyle;
        let ariaLabel;
        switch (action) {
            case REMOVE_ACTION:
                buttonStyle = 'secondary';
                ariaLabel = removeLabel;
                break;
            case SELECTED_ACTION:
                buttonStyle = 'emphasis-outline';
                ariaLabel = selectedLabel;
                break;
            default:
                buttonStyle = 'primary';
                ariaLabel = selectLabel;
                break;
        }

        const renderedTableName = renderTableName(name);
        const renderedPricing = renderTablePrice(formattedPricePerYear, i18n.frequency);
        const renderedAction = renderTableAction(
            buttonLabel,
            buttonIcon,
            buttonStyle,
            isSelectedState,
            isAddState ? () => addDomain(item) : () => removeDomain(item),
            `${action.toLowerCase()}-${name}`,
            ariaLabel
        );

        return (
            <tr {...n('tableRow').props} key={name}>
                {smallDown ? (
                    <td {...n('tableCell').props}>
                        <span {...n('tableContent').props}>
                            {renderedTableName}
                            {renderedPricing}
                            {renderedAction}
                        </span>
                    </td>
                ) : (
                    <React.Fragment>
                        <td {...n('tableCell', 'name').props}>
                            {renderedTableName}
                        </td>
                        <td {...n('tableCell', 'price').props}>
                            {renderedPricing}
                        </td>
                        <td {...n('tableCell', 'action').props}>
                            {renderedAction}
                        </td>
                    </React.Fragment>
                )}
            </tr>
        );
    };

    const renderRecommendDomains = hasDomainSuggestions ? suggestions.map(suggestion => {
        const isDomainSelected = (
            selectedDomains && (selectedDomains.findIndex(item => item.name === suggestion.name) !== -1)
        );
        const action = isDomainSelected ? SELECTED_ACTION : ADD_ACTION;

        return renderTableRow(suggestion, action);
    }) : (
        <tr {...n('tableRow').props}>
            <td {...n('tableCell', 'placeholder').props}>{i18n.recommendedPlaceholder}</td>
        </tr>
    );

    const renderAddedDomains = hasSelectedNames ? selectedDomains.map(
        selectedDomain => renderTableRow(selectedDomain, REMOVE_ACTION)
    ) : (
        <tr {...n('tableRow').props}>
            <td {...n('tableCell', 'placeholder').props}>{i18n.addedPlaceholder}</td>
        </tr>
    );

    const renderCta = item => {
        const { actionType, url, name, label, disabled, theme } = item;
        let action;
        switch (actionType) {
            case CTA_BUY:
            case CTA_BUY_MORE:
                action = () => handleBuyNowDomains(actionType);
                break;
            case CTA_DOMAIN_ADD_TO_CART:
                action = handleAddToCartDomains;
                break;
            default:
                break;
        }

        const buttonProps = {
            disabled,
            theme,
            onClick: action,
            url: !action ? url : null,
            className: n('footerButton').props.className,
            ctaType: actionType,
            ...n(name).props
        };

        return (
            <div {...n('footerItem').withTestId(name).props} key={name}>
                <ButtonIcon {...buttonProps}>
                    {label}
                </ButtonIcon>
            </div>
        );
    };

    return (
        <section {...n('wrapper').props}>
            <h1>{i18n.sectionTitle}</h1>
            <form {...n('form').props} onSubmit={handleSubmit(onSubmit)} noValidate>
                <div {...n('search').withTestId().props}>
                    <InputSearch
                        {...n('searchInput').props}
                        name="domain"
                        label={i18n.search}
                        placeholder={i18n.search}
                        defaultValue={defaultSearchValue}
                        hiddenLabel
                        submitLabel={i18n.search}
                        submitIconOnly={smallDown}
                        submitTextOnly={!smallDown}
                        inputRef={register({})}
                    />
                </div>
            </form>
            <div {...n('result').props}>
                <div {...n('resultItem').props}>
                    {(hasDomainSuggestions && !isLoading) && (
                        <span {...n('srOnly').props} role="status">
                            {suggestions.length === 1 ? i18n.domainFound : replacePlaceholders(i18n.domainsFound, {
                                resultsLength: suggestions.length
                            })}
                        </span>
                    )}
                    <table {...n('table').props}>
                        <caption {...n('tableCaption').props}>{i18n.recommendedTitle}</caption>
                        {hasDomainSuggestions && (
                            <thead {...n('tableHeader', 'hidden').props}>
                                <tr>
                                    <th scope="col">{i18n.recommendedDomainName}</th>
                                    <th scope="col">{i18n.domainPrice}</th>
                                    <th scope="col">{i18n.domainAction}</th>
                                </tr>
                            </thead>
                        )}
                        <tbody {...n('tableBody', 'suggestions').withTestId('suggestions').props}>{renderRecommendDomains}</tbody>
                    </table>
                </div>
                <div {...n('resultItem').props}>
                    <table {...n('table').props}>
                        <caption {...n('tableCaption').props}>{i18n.addedTitle}</caption>
                        {hasSelectedNames && (
                            <thead {...n('tableHeader', 'hidden').props}>
                                <tr>
                                    <th scope="col">{i18n.addedDomainName}</th>
                                    <th scope="col">{i18n.domainPrice}</th>
                                    <th scope="col">{i18n.domainAction}</th>
                                </tr>
                            </thead>
                        )}
                        <tbody {...n('tableBody', 'selected').withTestId('selected').props}>{renderAddedDomains}</tbody>
                    </table>
                </div>
            </div>
            {hasFooterCallToActions ? (
                <div {...n('footer').props}>
                    {callToActions && callToActions.map(renderCta)}
                </div>
            ) : null}
            <Preloader isLoading={isLoading} />
        </section>
    );
};

DomainAppComponent.schema = () => ({
    name: 'Domain App',
    title: 'uieditor.sfbComponent.domainApp.title',
    iconName: '',
    componentTitleKey: 'domainAppTitle',
    form: {
    },
    marketplaceData: {
        application: 'application',
        config: 'config'
    }
});

DomainAppComponent.propTypes = {
    data: PropTypes.shape(domainAppDataShape),
    fetchSuggestions: PropTypes.func
};

DomainAppComponent.defaultProps = {
    data: {
        config: {
            canRouteToV2: true
        },
        application: {
            config: {
                id: null
            },
            callToActions: {
                items: []
            },
            domains: {
                i18n: i18nDomainsMock
            }
        }
    },
    fetchSuggestions: null
};

export default withListener(DomainAppComponent);
