import { React, classnames, PropTypes } from '@gravityforms/libraries';
import Button from '../../elements/Button';
import Icon from '../../elements/Icon';
import Link from '../../elements/Link';
import Text from '../../elements/Text';
import { spacerClasses } from '@gravityforms/utils';

const { forwardRef, useState } = React;

/**
 * @module Alert
 * @description An alert component with predefined types and many customization arguments.
 *
 * @since 2.1.0
 *
 * @param {object}                     props                         The props for the component template.
 * @param {JSX.Element}                props.children                React element children.
 * @param {string}                     props.content                 The content of the alert.
 * @param {object}                     props.contentCustomAttributes Custom attributes for the content.
 * @param {string|Array|object}        props.contentCustomClasses    Custom classes for the content.
 * @param {string}                     props.ctaLabel                The label for the call-to-action button.
 * @param {string}                     props.ctaLink                 The link href for the call-to-action button.
 * @param {object}                     props.customAttributes        Any custom attributes.
 * @param {string|Array|object}        props.customClasses           An array of additional classes for the toggle.
 * @param {string}                     props.customIcon              An icon override for the defaults that are set based on type.
 * @param {string}                     props.customIconPrefix        The prefix for the custom override.
 * @param {string}                     props.dismissableAriaLabel    The aria-label for the dismiss button.
 * @param {string}                     props.dismissableTitle        The title for the dismiss button.
 * @param {boolean}                    props.hasCta                  Whether or not the alert has a call-to-action button.
 * @param {string}                     props.id                      Id for the alert, auto generated if not passed.
 * @param {boolean}                    props.isDismissable           Whether or not the alert is dismissable.
 * @param {boolean}                    props.isInline                Whether or not the alert is inline.
 * @param {string|number|Array|object} props.spacing                 The spacing for the component, string, number, object or array.
 * @param {string}                     props.theme                   Theme for the alert, primary or cosmos.
 * @param {string}                     props.type                    The type of the alert. Default, notice, success, error and accessibility.
 * @param {object|null}                ref                           Ref to the component.
 *
 * @return {JSX.Element} The alert component.
 *
 * @example
 * import Alert from '@gravityforms/components/react/admin/modules/Alert';
 * import Text from '@gravityforms/components/react/admin/elements/Text';
 *
 * return (
 *     <Alert>
 *         <Text content="Some text for my alert!">
 *     </Alert>
 * );
 *
 */
const Alert = forwardRef( ( {
	children = null,
	content = '',
	contentCustomAttributes = {},
	contentCustomClasses = [],
	ctaLabel = '',
	ctaLink = '',
	customAttributes = {},
	customClasses = [],
	customIcon = '',
	customIconPrefix = 'gravity-component-icon',
	dismissableAriaLabel = '',
	dismissableTitle = '',
	hasCta = false,
	iconAttributes = {},
	iconClasses = [],
	isDismissable = false,
	isInline = false,
	spacing = '',
	theme = 'cosmos',
	type = 'default',
}, ref ) => {
	const [ isDismissed, setIsDismissed ] = useState( false );
	const attributes = {
		className: classnames( {
			'gform-alert': true,
			[ `gform-alert--${ type }` ]: true,
			[ `gform-alert--theme-${ theme }` ]: true,
			'gform-alert--inline': isInline,
			...spacerClasses( spacing ),
		}, customClasses ),
		ref,
		...customAttributes,
	};
	const isCosmosTheme = 'cosmos' === theme;

	const customIconAttributes = {
		'aria-hidden': 'true',
		...iconAttributes,
	};
	const customIconClasses = classnames( {
		'gform-alert__icon': true,
	}, iconClasses );

	let alertIcon = customIcon;
	let alertIconPreset = '';

	if ( ! customIcon ) {
		switch ( type ) {
			case 'default':
				alertIcon = 'campaign';
				break;
			case 'info':
				alertIcon = isCosmosTheme ? 'information-simple' : 'circle-notice-fine';
				alertIconPreset = isCosmosTheme ? 'status-info' : '';
				break;
			case 'notice':
				alertIcon = isCosmosTheme ? 'exclamation-simple' : 'circle-notice-fine';
				alertIconPreset = isCosmosTheme ? 'status-info' : '';
				break;
			case 'success':
				alertIcon = isCosmosTheme ? 'checkmark-simple' : 'circle-check-fine';
				alertIconPreset = isCosmosTheme ? 'status-correct' : '';
				break;
			case 'error':
				alertIcon = isCosmosTheme ? 'exclamation-simple' : 'circle-error-fine';
				alertIconPreset = isCosmosTheme ? 'status-error' : '';
				break;
			case 'incorrect':
				alertIcon = isCosmosTheme ? 'exclamation-simple' : 'circle-error-fine';
				alertIconPreset = isCosmosTheme ? 'status-incorrect' : '';
				break;
			case 'accessibility':
				alertIcon = 'accessibility';
				break;
		}
	}

	const contentAttributes = {
		content,
		customClasses: classnames(
			[ 'gform-alert__message' ],
			contentCustomClasses,
		),
		tagName: 'p',
		...contentCustomAttributes,
	};

	return ! isDismissed
		? (
			<div { ...attributes }>
				<Icon
					customAttributes={ customIconAttributes }
					customClasses={ customIconClasses }
					icon={ alertIcon }
					iconPrefix={ customIconPrefix }
					preset={ alertIconPreset }
				/>
				<div className="gform-alert__message-wrap">
					<Text { ...contentAttributes }>{ children }</Text>
					{ hasCta &&
						<Link
							content={ ctaLabel }
							customClasses={ [ 'gform-alert__cta', 'gform-button', 'gform-button--white', 'gform-button--size-xs' ] }
							href={ ctaLink }
							target="_blank"
						/>
					}
				</div>
				{ isDismissable &&
					<Button
						ariaLabel={ dismissableAriaLabel }
						customAttributes={ {
							title: dismissableTitle,
						} }
						customClasses={ [ 'gform-alert__dismiss' ] }
						icon="delete"
						onClick={ () => {
							setIsDismissed( true );
						} }
					/>
				}
			</div>
		) : null;
} );

Alert.propTypes = {
	children: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.node ),
		PropTypes.node,
	] ),
	content: PropTypes.string,
	contentCustomAttributes: PropTypes.object,
	contentCustomClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	ctaLabel: PropTypes.string,
	ctaLink: PropTypes.string,
	customAttributes: PropTypes.object,
	customClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	customIcon: PropTypes.string,
	customIconPrefix: PropTypes.string,
	dismissableAriaLabel: PropTypes.string,
	dismissableTitle: PropTypes.string,
	hasCta: PropTypes.bool,
	iconAttributes: PropTypes.object,
	iconClasses: PropTypes.array,
	isDismissable: PropTypes.bool,
	isInline: PropTypes.bool,
	spacing: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.number,
		PropTypes.array,
		PropTypes.object,
	] ),
	theme: PropTypes.string,
	type: PropTypes.string,
};

Alert.displayName = 'Alert';

export default Alert;
