/**
 * WordPress dependencies
 */
import {
	BaseControl,
	Button,
	TextControl,
	SelectControl,
} from '@safe-wordpress/components';
import { useInstanceId } from '@safe-wordpress/compose';
import { useDispatch, useSelect } from '@safe-wordpress/data';
import { _x } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import clsx from 'clsx';
import {
	CssSelectorFinder,
	ConversionActionScope,
	ErrorText,
} from '@nab/components';
import { usePageAttribute } from '@nab/data';
import type { CAEditProps, Maybe } from '@nab/types';

// NOTE. Dependency loop with @nab package.
import type { store as editorStore } from '@nab/editor';
const NAB_EDITOR = 'nab/editor' as unknown as typeof editorStore;

/**
 * Internal dependencies
 */
import './edit.scss';
import type { Attributes } from './types';

export const Edit = ( {
	attributes: { mode, value },
	scope,
	errors,
	setAttributes,
	setScope,
}: CAEditProps< Attributes > ): JSX.Element => {
	const instanceId = useInstanceId( Edit );
	const alternatives = useAlternatives();
	const [ isCssFinderOpen, openCssFinder ] = useCssFinder( instanceId );
	const cssFinderUrl = useCssFinderUrl();
	const { saveExperiment } = useDispatch( NAB_EDITOR );

	const textControlId = `nab-click-action__value-${ instanceId }`;

	return (
		<>
			<SelectControl
				label={ _x( 'Matching Mode', 'text', 'nelio-ab-testing' ) }
				options={ OPTIONS }
				value={ mode }
				onChange={ ( newMode ) => setAttributes( { mode: newMode } ) }
			/>

			<BaseControl
				id={ textControlId }
				className={ clsx( {
					'nab-conversion-action__field--has-errors': errors.value,
				} ) }
				label={ LABELS[ mode ] }
				help={ <ErrorText value={ errors.value } /> }
			>
				<div className="nab-click-conversion-action">
					<TextControl
						id={ textControlId }
						className="nab-click-conversion-action__value"
						value={ value }
						onChange={ ( newValue ) =>
							setAttributes( { value: newValue } )
						}
					/>

					{ !! cssFinderUrl && (
						<>
							<Button
								variant="secondary"
								className="nab-click-conversion-action__button"
								onClick={ () =>
									void saveExperiment().then( () =>
										openCssFinder( true )
									)
								}
							>
								{ mode === 'css'
									? _x(
											'Explore',
											'command',
											'nelio-ab-testing'
									  )
									: _x(
											'View',
											'command',
											'nelio-ab-testing'
									  ) }
							</Button>

							{ isCssFinderOpen && (
								<CssSelectorFinder
									initialUrl={ cssFinderUrl }
									alternatives={ alternatives }
									initialValue={ value }
									initialMode={ mode }
									onAccept={ ( newMode, newValue ) =>
										setAttributes( {
											mode: newMode,
											value: newValue,
										} )
									}
									onClose={ () => openCssFinder( false ) }
								/>
							) }
						</>
					) }
				</div>
			</BaseControl>

			<ConversionActionScope
				scope={ scope }
				setScope={ setScope }
				error={ errors._scope }
			/>
		</>
	);
};

// =====
// HOOKS
// =====

const useAlternatives = () =>
	useSelect(
		( select ) => select( NAB_EDITOR )?.getAlternatives() || [],
		[]
	);

const useCssFinder = ( instanceId: string | number ) => {
	instanceId = `${ instanceId }`;
	const [ finderId, setFinderId ] = usePageAttribute(
		'css-selector/openedCssSelectorFinderId',
		''
	);

	const isOpen = finderId === instanceId;
	const open = ( v: boolean ) => setFinderId( v ? instanceId : '' );

	return [ isOpen, open ] as const;
};

const useCssFinderUrl = () =>
	useSelect(
		( select ): Maybe< string > =>
			select( NAB_EDITOR )?.getAlternative( 'control' ).links.preview ||
			undefined,
		[]
	);

// =======
// HELPERS
// =======

const LABELS: Record< Attributes[ 'mode' ], string > = {
	id: _x( 'Element ID', 'text', 'nelio-ab-testing' ),
	class: _x( 'CSS Class', 'text', 'nelio-ab-testing' ),
	css: _x( 'CSS Selector', 'text', 'nelio-ab-testing' ),
};

const OPTIONS = Object.keys( LABELS )
	.map( ( v ) => v as Attributes[ 'mode' ] )
	.map( ( value ) => ( {
		value,
		label: LABELS[ value ],
	} ) );
