import { consoleInfo, getNode, objectToAttributes, trigger, uniqueId, spacerClasses } from '@gravityforms/utils';

/**
 * @function textTemplate
 * @description A text component to use wherever texts are needed.
 *
 * @since 2.2.0
 *
 * @param {object} options               The options for the text component template.
 * @param {string} options.content       Content for the text.
 * @param {Array}  options.customClasses An array of additional classes for the text.
 * @param {string} options.id            Id for the text, auto generated if not passed.
 * @param {string} options.size          Size string, check storybook for available ones.
 * @param {string} options.spacing       Spacing for the component.
 * @param {string} options.tagName       Tag for the text, h2 if not passed.
 * @param {string} options.weight        The font weight for the text, regular, semibold or bold.
 *
 * @return {string} The html for the text component.
 * @example
 * import { textTemplate } from '@gravityforms/components/html/admin/elements/Text';
 *
 * function Example() {
 *      const textTemplateHTML = textTemplate( options );
 *      document.body.insertAdjacentHTML( 'beforeend', textTemplateHTML );
 * }
 *
 */
export const textTemplate = ( {
	content = '',
	customClasses = [],
	id = '',
	size = 'text-md',
	spacing = '',
	tagName = 'div',
	weight = 'regular',
} ) => {
	const componentProps = {
		class: [
			'gform-common-text',
			`gform-typography--size-${ size }`,
			`gform-typography--weight-${ weight }`,
			...customClasses,
			...Object.keys( spacerClasses( spacing ) ),
		],
		id,
	};

	return `<${ tagName } ${ objectToAttributes( componentProps ) }>${ content }</${ tagName }>`;
};

/**
 * @class Heading
 * @description A text component.
 *
 * @since 2.2.0
 *
 * @param {object}                     options                Component options.
 * @param {string}                     options.content        The content for the text. Can contain html.
 * @param {string|Array|object}        options.customClasses  Custom classes to apply to the text.
 * @param {string|Array|object}        options.id             The id for the text div, auto genned if not supplied.
 * @param {string}                     options.rendered       Is the component already rendered in the dom, eg by php?
 * @param {string}                     options.renderOnInit   Render the component on init of the class?
 * @param {string}                     options.size           Size string, check storybook for available ones.
 * @param {string|number|Array|object} options.spacing        The spacing classes to apply.
 * @param {string}                     options.tagName        The tag used for the container element.
 * @param {string}                     options.target         The target to render to. Any valid css selector string.
 * @param {string}                     options.targetPosition The insert position for the component relative to the target.
 * @param {string}                     options.weight         The font weight for the text.
 *
 * @return {Class} The text class instance.
 *
 * @example
 * import Text from '@gravityforms/components/html/admin/elements/Text';
 *
 * function Example() {
 *      const labelInstance = new Text( {
 *          content: 'Text content',
 *          tagName: 'div',
 *          weight: 'regular',
 *          target: '#example-target',
 *      } );
 * }
 *
 */
export default class Text {
	/**
	 * @description The class constructor.
	 *
	 * @param {object} options The options object. Check defaults for descriptions.
	 */
	constructor( options = {} ) {
		this.options = {};
		Object.assign(
			this.options,
			{
				content: '',
				customClasses: [],
				id: uniqueId( 'gform-text' ),
				rendered: false,
				renderOnInit: true,
				size: 'text-md',
				spacing: '',
				tagName: 'div',
				target: '', // the target to render to. Any valid css selector string.
				targetPosition: 'afterbegin', // the insert position for the target
				weight: 'regular', // the weight for the text.
			},
			options
		);

		trigger( { event: 'gform/text/pre_init', native: false, data: { instance: this } } );

		this.elements = {};

		if ( this.options.renderOnInit ) {
			this.init();
		}
	}

	/**
	 * @function render
	 * @description Renders the text into the dom.
	 *
	 * @since 2.2.0
	 *
	 * @return {string}
	 */
	render() {
		const { rendered, target, targetPosition } = this.options;

		if ( ! rendered ) {
			const renderTarget = getNode( target, document, true );

			renderTarget.insertAdjacentHTML(
				targetPosition,
				textTemplate( this.options )
			);
		}

		this.elements.text = getNode( `#${ this.options.id }`, document, true );
	}

	/**
	 * @function init
	 * @description Initialize the text.
	 *
	 * @since 2.2.0
	 *
	 * @return {void}
	 */
	init() {
		this.render();

		trigger( { event: 'gform/text/post_render', native: false, data: { instance: this } } );

		consoleInfo( `Gravity Forms Admin: Initialized text component on ${ this.options.target }.` );
	}
}
