import { React, PropTypes, ReactRouter } from '@gravityforms/libraries';
import Box from '../../elements/Box';
import Button from '../../elements/Button';
import Checkbox from '../../elements/Checkbox';
import Gravatar from '../../modules/Gravatar';
import Heading from '../../elements/Heading';
import Input from '../../elements/Input';
import Label from '../../elements/Label';
import Link from '../../elements/Link';
import Radio from '../../elements/Radio';
import Select from '../../elements/Select';
import StatusIndicator from '../../elements/StatusIndicator';
import Text from '../../elements/Text';
import Textarea from '../../elements/Textarea';
import Toggle from '../../elements/Toggle';

const { Fragment, memo, useCallback } = React;
const { RouterLink, RouterNavLink } = ReactRouter;

/**
 * @module GridCell
 * @description Renders a grid cell based on passed field data from the server.
 *
 * @since 3.3.0
 *
 * @param {object}   props            Component props.
 * @param {object}   data             Cell data.
 * @param {Function} handleGridClicks Passed handler for grid clicks if the field type supports it.
 * @param {Function} setGridData      Passed handler for grid changes if the field type supports it.
 *
 * @return {JSX.Element} The Grid Cell component.
 */
const GridCell = memo( ( {
	data = {},
	handleGridClicks = () => {},
	setGridData = () => {},
} ) => {
	const handleChange = useCallback( ( value ) => {
		if ( data.props && data.props.name ) {
			setGridData( data.props.name, value );
		}
	}, [ data.props, setGridData ] );

	const handleClicks = useCallback( () => {
		handleGridClicks( data.props );
	}, [ data.props, handleGridClicks ] );

	const renderNestedFields = ( entries ) => {
		if ( ! entries ) {
			return null;
		}

		return entries.map( ( nestedData, index ) => (
			<GridCell key={ index } data={ nestedData } setGridData={ setGridData } handleGridClicks={ handleGridClicks } />
		) );
	};

	let component = null;
	if ( data.external ) {
		const External = data.component;
		component = <External { ...data.props } />;
	} else {
		switch ( data.component ) {
			case 'Box':
				component = <Box { ...data.props }>{ renderNestedFields( data.components ) }</Box>;
				break;
			case 'Button':
				component = <Button { ...data.props } onClick={ handleClicks } />;
				break;
			case 'Checkbox':
				component = <Checkbox { ...data.props } onChange={ handleChange } />;
				break;
			case 'Gravatar':
				component = <Gravatar { ...data.props } />;
				break;
			case 'Heading':
				component = <Heading { ...data.props } />;
				break;
			case 'Input':
				component = <Input { ...data.props } onChange={ handleChange } />;
				break;
			case 'Label':
				component = <Label { ...data.props } />;
				break;
			case 'Link':
				component = <Link { ...data.props } />;
				break;
			case 'Radio':
				component = <Radio { ...data.props } onChange={ handleChange } />;
				break;
			case 'RouterLink':
				component = <RouterLink { ...data.props }>{ data.props.label }</RouterLink>;
				break;
			case 'RouterNavLink':
				component = <RouterNavLink { ...data.props }>{ data.props.label }</RouterNavLink>;
				break;
			case 'Select':
				component = <Select { ...data.props } onChange={ handleChange } />;
				break;
			case 'StatusIndicator':
				component = <StatusIndicator { ...data.props } />;
				break;
			case 'Text':
				component = <Text { ...data.props } />;
				break;
			case 'Textarea':
				component = <Textarea { ...data.props } onChange={ handleChange } />;
				break;
			case 'Toggle':
				component = <Toggle { ...data.props } onChange={ handleChange } />;
				break;
			default:
				component = null;
		}
	}

	return (
		<Fragment>
			{ component }
		</Fragment>
	);
} );

GridCell.propTypes = {
	data: PropTypes.object,
	handleGridClicks: PropTypes.func,
	setFieldData: PropTypes.func,
};

export default GridCell;
