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

/**
 * External dependencies
 */
import { CodeEditor } from '@nab/components';
import { usePluginSetting } from '@nab/data';
import { createScopeRule, getLocalUrlError } from '@nab/utils';
import type {
	CustomPhpScopeRule,
	CustomUrlScopeRule,
	Maybe,
	ScopeRule,
} from '@nab/types';

/**
 * Internal dependencies
 */
import './style.scss';
import { CustomUrlScope } from '../custom-url-scope';
import { store as NAB_EDITOR } from '../../../../store';

export type UrlsOrPhpScopeProps = {
	readonly rules: ReadonlyArray< CustomUrlScopeRule | CustomPhpScopeRule >;
};

export const UrlsOrPhpScope = ( {
	rules,
}: UrlsOrPhpScopeProps ): JSX.Element => {
	const { setScopeRules } = useDispatch( NAB_EDITOR );

	const [ firstRule ] = rules;
	if ( isCustomPhpScopeRule( firstRule ) ) {
		return <PhpCode rule={ firstRule } />;
	}

	return (
		<div>
			<CustomUrlScope
				rules={ rules.filter( isCustomUrlScopeRule ) }
				scopeSupport="urls"
			/>
			<br />
			<p>
				{ _x(
					'Alternatively, you can specify where variants should be visible using PHP.',
					'text',
					'nelio-ab-testing'
				) }
			</p>
			<Button
				variant="secondary"
				onClick={ () =>
					setScopeRules( [
						createScopeRule( {
							type: 'php-snippet',
							value: {
								priority: 'low',
								snippet: 'return true;',
								previewUrl: '',
							},
						} ),
					] )
				}
			>
				{ _x( 'Define Scope in PHP', 'command', 'nelio-ab-testing' ) }
			</Button>
		</div>
	);
};

// ============
// HELPER VIEWS
// ============

const PhpCode = ( {
	rule,
}: {
	readonly rule: CustomPhpScopeRule;
} ): JSX.Element => {
	const { setScopeRules } = useDispatch( NAB_EDITOR );
	const editRule = (
		value: Partial< CustomPhpScopeRule[ 'attributes' ][ 'value' ] >
	) =>
		setScopeRules( [
			{
				...rule,
				attributes: {
					...rule.attributes,
					value: { ...rule.attributes.value, ...value },
				},
			},
		] );

	const { priority, snippet, errorMessage, warningMessage, previewUrl } =
		rule.attributes.value;
	const homeUrl = usePluginSetting( 'homeUrl' );
	const previewUrlError = getLocalUrlError( previewUrl, homeUrl );

	return (
		<div className="nab-edit-experiment-php-scope">
			<SelectControl
				className="nab-edit-experiment-php-scope__hook"
				value={ priority }
				options={ PRIORITY_OPTIONS }
				onChange={ ( value ) => editRule( { priority: value } ) }
			/>
			<div className="nab-edit-experiment-php-scope__snippet">
				<CodeEditor
					language="php"
					withBorder
					before="function is_test_active(): bool {"
					value={ snippet }
					after="}"
					onChange={ ( value ) =>
						editRule( {
							snippet: value,
							errorMessage: undefined,
							warningMessage: undefined,
							validateSnippet: true,
						} )
					}
				/>
			</div>
			{ !! errorMessage && (
				<p className="nab-edit-experiment-php-scope__snippet-error">
					{ sprintf(
						/* translators: %s: Error message. */
						'There’s a problem with your code: %s',
						errorMessage
					) }
				</p>
			) }
			{ !! warningMessage && (
				<p className="nab-edit-experiment-php-scope__snippet-error">
					{ sprintf(
						/* translators: %s: Error message. */
						'There might be a problem with your code: %s',
						warningMessage
					) }
				</p>
			) }
			<TextControl
				label={ _x( 'Preview URL', 'text', 'nelio-ab-testing' ) }
				value={ previewUrl }
				onChange={ ( value ) => editRule( { previewUrl: value } ) }
			/>
			{ previewUrlError && (
				<p className="nab-edit-experiment-php-scope__preview-error">
					{ previewUrlError }
				</p>
			) }
		</div>
	);
};

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

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

const PRIORITY_OPTIONS = [
	{
		value: 'high' as const,
		label: sprintf(
			/* translators: %s: Hook name. */
			_x( 'Run on “%s”', 'command', 'nelio-ab-testing' ),
			'plugins_loaded'
		),
	},
	{
		value: 'mid' as const,
		label: sprintf(
			/* translators: %s: Hook name. */
			_x( 'Run on “%s”', 'command', 'nelio-ab-testing' ),
			'parse_query'
		),
	},
	{
		value: 'low' as const,
		label: sprintf(
			/* translators: %s: Hook name. */
			_x( 'Run on “%s”', 'command', 'nelio-ab-testing' ),
			'wp'
		),
	},
];

const CHECKER: Record< CustomUrlScopeRule[ 'attributes' ][ 'type' ], true > = {
	exact: true,
	partial: true,
	'partial-not-included': true,
	different: true,
};
export const isCustomUrlScopeRule = (
	r: Maybe< ScopeRule >
): r is CustomUrlScopeRule =>
	( CHECKER as Record< string, boolean > )[ r?.attributes.type ?? '' ] ||
	false;

export const isCustomPhpScopeRule = (
	r: Maybe< ScopeRule >
): r is CustomPhpScopeRule => 'php-snippet' === r?.attributes.type;
