import React from 'react';
import PropTypes from 'prop-types';
import { useForm } from 'react-hook-form';
import { CSSTransition } from 'react-transition-group';
import { GlobalAlerts } from '../global-alerts/GlobalAlerts';
import { createNamespace } from '../../tools/namingTools';
import { navigateTo } from '../../tools/urlTools';
import { handleAddDomainToCartAction } from '../../tools/callToActions';
import { useResponsive } from '../../tools/widths/useResponsive';
import { useDomainSuggestions } from '../../tools/ajax/useDomainSuggestions';
import { replacePlaceholders } from '../../tools/stringTools';
import { getDomainActionLabel } from '../../tools/components/domainApp';
import { useAppCartItem } from './hooks/useAppCartItem';
import { CTA_ADD_TO_CART, CTA_ADD_TO_CART_CROSS_SELL, CART_URL } from '../../constants/actions';
import { THEME_PRIMARY } from '../../constants/buttons';
import { productAssociatedDomainDataShape } from '../../constants/components/prop-types/product-associated-domain';
import { i18nMock } from '../../../mocks/i18n';
import { i18nMock as i18nDomainsMock } from '../../../mocks/application/domains/i18n';
import { i18nMock as i18nCrossSellManagementMock } from '../../../mocks/application/crossSellManagement/i18n';

import Preloader from '../../atoms/preloader/Preloader';
import ButtonIcon from '../../atoms/button-icon/ButtonIcon';
import Badge from '../../atoms/badge/Badge';
import InputSearch from '../../atoms/input-search/InputSearch';
import CartSelectionPreview from '../../atoms/cart-selection-preview/CartSelectionPreview';
import { alertTypes } from '../../atoms/alert/Alert';
import StatusMessage from '../../atoms/status-message/StatusMessage';

import './styles/ProductAssociatedDomain.scss';

import withListener from '../withListener';

const n = createNamespace('ProductAssociatedDomain');

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>
    );
};

export const ProductAssociatedDomainComponent = ({
    data: {
        application: {
            crossSellManagement = {},
            domains,
            config: appConfig
        },
        cart,
        i18n: globalI18n
    },
    fetchSuggestions
}) => {
    const { i18n = {} } = { ...crossSellManagement };
    const i18nWithDefaults = {
        ...ProductAssociatedDomainComponent.defaultProps.data.application.crossSellManagement.i18n,
        ...i18n
    };
    const globalI18nWithDefaults = {
        ...ProductAssociatedDomainComponent.defaultProps.data.i18n,
        ...globalI18n
    };
    const domainsI18nWithDefaults = {
        ...ProductAssociatedDomainComponent.defaultProps.data.application.domains.i18n,
        ...domains.i18n
    };

    const { smallDown } = useResponsive();
    const { handleSubmit, register } = useForm();
    const {
        suggestions,
        setSearchValue,
        isLoading,
        isError,
        isWarning,
        statusMessage,
        dismissMessage
    } = useDomainSuggestions(
        domains,
        fetchSuggestions,
        {
            title: globalI18nWithDefaults.genericErrorMessage
        },
        {
            title: domainsI18nWithDefaults.noResultMessageTitle,
            description: domainsI18nWithDefaults.noResultMessageDescription
        }
    );
    // combine cart info with application data, to get the complete picture of the item added to the cart
    const appCartItem = useAppCartItem(crossSellManagement.selectedEdition, cart);

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

    const onSkip = () => {
        // depending on the user's provenance, we redirect to the checkout or to the app's page when skipping
        switch (crossSellManagement.previousCTA?.actionType) {
            case CTA_ADD_TO_CART_CROSS_SELL:
            case CTA_ADD_TO_CART: {
                // if add to cart was clicked, go back to app, to continue shopping
                navigateTo(crossSellManagement.productUrl);
                break;
            }
            default: {
                // when BUY_NOW was clicked, we must redirect to checkout
                navigateTo(CART_URL);
            }
        }
    };
    const onBuy = item => {
        handleAddDomainToCartAction(
            appCartItem.id,
            appConfig.id,
            crossSellManagement.selectedEdition,
            [...crossSellManagement.selectedAddons],
            [
                {
                    pricingPlan: item.editionPricingUuid,
                    name: item.name
                }
            ]
        );
    };

    const hasDomainSuggestions = Boolean(suggestions && suggestions.length);

    const renderTableRow = item => {
        const { name, formattedPricePerYear, available } = item;
        const { selectLabel } = getDomainActionLabel(name, domainsI18nWithDefaults);
        const renderedTableName = <span {...n('name', !available && 'unavailable').props}>{name}</span>;
        const renderedPricing = available ? (
            renderTablePrice(formattedPricePerYear, i18nWithDefaults.frequency)
        ) : (
            <Badge label={i18nWithDefaults.unavailable} />
        );
        const renderedAction = available && (
            <span {...n('action').withTestId(name).props}>
                <ButtonIcon
                    {...n('actionButton').props}
                    theme="emphasis"
                    aria-label={selectLabel}
                    onClick={() => onBuy(item)}
                >
                    {i18nWithDefaults.select}
                </ButtonIcon>
            </span>
        );

        return (
            <tr {...n('tableRow', !available && 'unavailable').props} key={name}>
                {smallDown ? (
                    <td {...n('tableCell').props}>
                        <span {...n('tableContent').props}>
                            {renderedTableName}
                            {renderedPricing}
                            {renderedAction}
                        </span>
                    </td>
                ) : (
                    <>
                        <td {...n('tableCell', 'name').props}>
                            {renderedTableName}
                        </td>
                        <td {...n('tableCell', 'price').props} colSpan={available ? 1 : 2}>
                            {renderedPricing}
                        </td>
                        {available && (
                            <td {...n('tableCell', 'action').props}>
                                {renderedAction}
                            </td>
                        )}
                    </>
                )}
            </tr>
        );
    };

    const renderRecommendDomains = hasDomainSuggestions ? (
        <>
            <span {...n('srOnly').props} role="status">
                {suggestions.length === 1
                    ? domainsI18nWithDefaults.domainFound
                    : replacePlaceholders(domainsI18nWithDefaults.domainsFound, { resultsLength: suggestions.length })}
            </span>
            <table {...n('table').props}>
                <caption {...n('tableCaption', 'hidden').props}>{domainsI18nWithDefaults.recommendedTitle}</caption>
                <thead {...n('tableHeader', 'hidden').props}>
                    <tr>
                        <th scope="col">{domainsI18nWithDefaults.domainName}</th>
                        <th scope="col">{domainsI18nWithDefaults.domainPrice}</th>
                        <th scope="col">{domainsI18nWithDefaults.domainAction}</th>
                    </tr>
                </thead>
                <tbody {...n('tableBody', 'suggestions').withTestId('suggestions').props}>
                    {suggestions.sort(
                        (a, b) => (a.available && 1) || (b.available && -1)
                    ).map(suggestion => renderTableRow(suggestion))}
                </tbody>
            </table>
        </>
    ) : (
        <CSSTransition
            in={isWarning}
            appear
            timeout={400}
            unmountOnExit
        >
            <div {...n('error').withTestId().props}>
                {statusMessage && (
                    <StatusMessage
                        title={statusMessage.title}
                        details={statusMessage.description}
                        scrollIntoView
                    />
                )}
            </div>
        </CSSTransition>
    );

    return (
        <section {...n('wrapper').props}>
            <h1 {...n('mainTitle', 'hidden').props}>{domainsI18nWithDefaults.sectionTitle}</h1>
            {appCartItem && (
                <div {...n('preview').props}>
                    <div {...n('previewContent').props}>
                        <CartSelectionPreview cart={appCartItem} i18n={i18nWithDefaults} />
                    </div>
                </div>
            )}
            <div {...n('result').props}>
                <div {...n('resultContent').props}>
                    <h2 {...n('title').props}>{i18nWithDefaults.sectionTitle}</h2>
                    <div {...n('box').props}>
                        <form {...n('search').props} onSubmit={handleSubmit(onSubmit)} noValidate>
                            <fieldset {...n('fieldset').props}>
                                <legend {...n('legend').props}>{i18nWithDefaults.sectionDescription}</legend>
                                <InputSearch
                                    {...n('searchInput').withTestId().props}
                                    name="domain"
                                    placeholder={i18nWithDefaults.search}
                                    submitLabel={i18nWithDefaults.searchCta}
                                    height={50}
                                    submitColorTheme={THEME_PRIMARY}
                                    inputRef={register({})}
                                    hiddenLabel
                                    submitTextOnly
                                    onChange={dismissMessage}
                                />
                            </fieldset>
                        </form>
                        {renderRecommendDomains}
                        <div {...n('skip').withTestId().props}>
                            <ButtonIcon
                                {...n('skipButton').props}
                                onClick={onSkip}
                                theme="secondary"
                                aria-label={domainsI18nWithDefaults.skipBuyingDomain}
                            >
                                {i18nWithDefaults.skip}
                            </ButtonIcon>
                        </div>
                    </div>
                </div>
            </div>
            <Preloader isLoading={isLoading} />

            {isError && (
                <GlobalAlerts
                    data={{
                        rawAlerts: [
                            {
                                message: statusMessage.title,
                                alertType: alertTypes.ERROR_ALERT
                            }
                        ]
                    }}
                    onClosed={dismissMessage}
                />
            )}
        </section>
    );
};

ProductAssociatedDomainComponent.schema = () => ({
    marketplaceData: {
        application: 'application',
        config: 'config',
        cart: 'cart',
        i18n: 'i18n'
    }
});

ProductAssociatedDomainComponent.propTypes = {
    data: PropTypes.shape(productAssociatedDomainDataShape),
    fetchSuggestions: PropTypes.func
};

ProductAssociatedDomainComponent.defaultProps = {
    data: {
        config: {},
        application: {
            domains: {
                i18n: i18nDomainsMock
            },
            crossSellManagement: {
                i18n: i18nCrossSellManagementMock
            }
        },
        cart: {},
        i18n: i18nMock
    },
    fetchSuggestions: null
};

export default withListener(ProductAssociatedDomainComponent);
