import React from 'react';
import PropTypes from 'prop-types';
import Icon from '../icon/Icon';
import { createNamespace } from '../../tools/namingTools';
import { ratingsSummaryDefaults } from '../../constants/default-props/ratings';
import { replacePlaceholders } from '../../tools/stringTools';
// IMPORTANT: (s)css should be imported after other atoms/components
import './styles/rating.scss';

const n = createNamespace('Rating');

const Rating = ({
    caption,
    title,
    rating,
    numRatings,
    ratingScore,
    displayRatingNumber,
    displayRatingCaption,
    showLongNumRatings,
    starWidth,
    isSelected,
    i18n,
    i18nRating
}) => {
    const ratingValue = Number.parseFloat(rating) || 0;
    const numRatingsValue = numRatings || 0;
    const i18nWithDefaults = { ...Rating.defaultProps.i18n, ...i18n };

    // don't display decimal when integer
    const ratingDisplay = Number.isInteger(ratingValue) ? ratingValue : ratingValue.toFixed(1);

    const starsArray = [...Array(ratingScore).keys()];

    const isMaxRating = rating === starsArray.length;
    const shouldDisplayCaption = displayRatingCaption && !isMaxRating;
    const hasA11yCaption = Boolean(i18nRating?.label || caption);

    const componentVariables = {
        'rating-fullstars': Math.floor(ratingValue),
        'rating-partialstar': ratingValue % 1,
        ...starWidth && {
            'rating-star-width': `${starWidth}px`
        }
    };

    const renderStars = status => (
        <div {...n('star', status).props}>
            {starsArray.map(index => (
                <Icon {...n('starItem', status).withTestId().withE2EId().props} key={`ratingStar${index}`} type="star" />
            ))}
        </div>
    );

    const renderNumRatings = () => {
        if (!numRatings) {
            return null;
        }
        let numRatingsText = `(${numRatings})`;
        if (showLongNumRatings) {
            numRatingsText = `(${numRatings}) ${i18nWithDefaults.reviews}`;
        }

        return <span {...n('numberOfRatings').withTestId().withE2EId().props} aria-hidden={hasA11yCaption}>{numRatingsText}</span>;
    };

    const a11yLabel = () => {
        let label;

        if (i18nRating) {
            label = replacePlaceholders(i18nRating.label, {
                userRating: ratingValue,
                nrUserReviews: numRatingsValue
            });
        } else if (caption) {
            label = `${title} ${caption}`;
        }

        return (i18nRating || caption) && (
            <span {...n('a11yCaption').withTestId().props}>
                {label}
            </span>
        );
    };

    return (
        <div {...n('wrapper').withTestId().withVariables(componentVariables).withE2EId().props}>
            <div {...n('stats').withE2EId().props} aria-hidden={hasA11yCaption}>
                <div {...n('score').withE2EId().props}>
                    {renderStars('neutral')}
                    {ratingValue > 0 && (
                        <div {...n('mask').withE2EId().props}>
                            {renderStars(isSelected ? 'selected' : 'positive')}
                        </div>
                    )}
                </div>
            </div>
            {displayRatingNumber && (
                <span {...n('rating').withTestId().withE2EId().props} aria-hidden={hasA11yCaption}>{ratingDisplay}</span>
            )}
            {shouldDisplayCaption && (
                <span {...n('caption').withTestId().withE2EId().props} aria-hidden={hasA11yCaption}>{i18nWithDefaults.andUp}</span>
            )}
            {renderNumRatings()}
            {a11yLabel()}
        </div>
    );
};

Rating.propTypes = {
    title: PropTypes.string,
    rating: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    numRatings: PropTypes.number,
    caption: PropTypes.string,
    ratingScore: PropTypes.number,
    displayRatingNumber: PropTypes.bool,
    displayRatingCaption: PropTypes.bool,
    showLongNumRatings: PropTypes.bool,
    starWidth: PropTypes.number,
    isSelected: PropTypes.bool,
    i18n: PropTypes.shape({
        reviews: PropTypes.string,
        andUp: PropTypes.string
    }),
    i18nRating: PropTypes.shape({
        label: PropTypes.string
    })
};

Rating.defaultProps = {
    ...ratingsSummaryDefaults,
    ratingScore: 5,
    starWidth: null,
    displayRatingNumber: true,
    displayRatingCaption: false,
    showLongNumRatings: false,
    isSelected: false,
    i18n: {
        reviews: 'Reviews',
        andUp: '& up'
    },
    i18nRating: null
};

export default Rating;
