/**
 * The per-post restriction configurator form.
 *
 * Field-for-field the same configuration as the "Restricted Content" Gutenberg
 * block (mode, access rules, plan feature), reusing the very same REST-backed
 * pickers, plus the denial behaviour a whole page needs: replace the content
 * with a message, or redirect the visitor somewhere else.
 */
import {
	Notice,
	SelectControl,
	TextControl,
	TextareaControl,
	ToggleControl,
	__experimentalNumberControl as NumberControl,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';

import {
	AsyncIdCombobox,
	AsyncTokenSelect,
	FeatureCombobox,
	StaticTokenSelect,
} from '@libs/access-controls';

import {
	DEFAULT_MESSAGE,
	ROLE_OPTIONS,
	STATUS_OPTIONS,
	warningFor,
} from './config';

function RestrictionSection( { title, className = '', children } ) {
	const classes = [
		'arraysubs-restriction-fields__section',
		className,
	]
		.filter( Boolean )
		.join( ' ' );

	return (
		<section className={ classes }>
			<h3 className="arraysubs-restriction-fields__section-title">
				{ title }
			</h3>
			<div className="arraysubs-restriction-fields__section-content">
				{ children }
			</div>
		</section>
	);
}

function DeniedSection( { config, isRestrict, set, update } ) {
	return (
		<RestrictionSection
			title={ __( 'When Access Is Denied', 'arraysubs' ) }
			className="arraysubs-restriction-fields__section--denied"
		>
			<SelectControl
				__next40pxDefaultSize
				__nextHasNoMarginBottom
				label={ __( 'What Should Happen', 'arraysubs' ) }
				value={ config.deniedAction }
				help={
					config.deniedAction === 'redirect'
						? __(
								'The visitor never sees this page — they are sent straight to the destination below.',
								'arraysubs'
						  )
						: __(
								'The visitor stays on this page, but the whole content is replaced with the message below.',
								'arraysubs'
						  )
				}
				options={ [
					{
						label: __(
							'Show a message instead of the content',
							'arraysubs'
						),
						value: 'message',
					},
					{
						label: __( 'Redirect to another page', 'arraysubs' ),
						value: 'redirect',
					},
				] }
				onChange={ set( 'deniedAction' ) }
			/>

			{ config.deniedAction === 'message' && (
				<TextareaControl
					__nextHasNoMarginBottom
					label={ __( 'Restricted Message', 'arraysubs' ) }
					help={ __(
						'Replaces the entire content for visitors who fail the rules. Leave empty to use the global default. You can use {site_name}, {login_link} and {pricing_link}.',
						'arraysubs'
					) }
					value={ config.message }
					placeholder={ DEFAULT_MESSAGE }
					onChange={ set( 'message' ) }
				/>
			) }

			{ config.deniedAction === 'redirect' && (
				<>
					<SelectControl
						__next40pxDefaultSize
						__nextHasNoMarginBottom
						label={ __( 'Redirect Destination', 'arraysubs' ) }
						value={ config.redirectType }
						options={ [
							{
								label: __( 'A page on this site', 'arraysubs' ),
								value: 'page',
							},
							{
								label: __( 'A custom URL', 'arraysubs' ),
								value: 'url',
							},
						] }
						onChange={ set( 'redirectType' ) }
					/>

					{ config.redirectType === 'page' && (
						<AsyncIdCombobox
							label={ __( 'Page', 'arraysubs' ) }
							help={ __(
								'Search any published page and pick where denied visitors land.',
								'arraysubs'
							) }
							type="posts"
							query={ { post_type: 'page' } }
							value={ config.redirectPageId }
							onChange={ ( id, label ) =>
								update( {
									redirectPageId: id,
									redirectPageLabel: label,
								} )
							}
							onResolveLabel={ ( label ) => {
								if ( label && label !== config.redirectPageLabel ) {
									update( {
										redirectPageLabel: label,
									} );
								}
							} }
						/>
					) }

					{ config.redirectType === 'url' && (
						<TextControl
							__next40pxDefaultSize
							__nextHasNoMarginBottom
							type="url"
							label={ __( 'Redirect URL', 'arraysubs' ) }
							help={ __(
								'Full URL including https://. Internal and external addresses both work.',
								'arraysubs'
							) }
							value={ config.redirectUrl }
							placeholder="https://example.com/pricing"
							onChange={ set( 'redirectUrl' ) }
						/>
					) }
				</>
			) }

			{ isRestrict && (
				<ToggleControl
					__nextHasNoMarginBottom
					label={ __( 'Require Login', 'arraysubs' ) }
					help={ __(
						'Logged-out visitors are denied before the rules are even checked.',
						'arraysubs'
					) }
					checked={ !! config.loginRequired }
					onChange={ set( 'loginRequired' ) }
				/>
			) }

			<ToggleControl
				__nextHasNoMarginBottom
				label={ __( 'Always Show To Admins', 'arraysubs' ) }
				help={ __(
					'Administrators bypass this restriction so a rule can never lock you out.',
					'arraysubs'
				) }
				checked={ !! config.showToAdmins }
				onChange={ set( 'showToAdmins' ) }
			/>
		</RestrictionSection>
	);
}

export default function RestrictionFields( { config, update } ) {
	const set = ( key ) => ( value ) => update( { [ key ]: value } );

	const isRestrict = config.mode === 'restrict';
	const isVisibility = config.mode === 'visibility';
	const showFeatureAmount =
		isRestrict &&
		config.feature &&
		[ 'min_total', 'min_single', 'custom' ].includes( config.featureMatch );
	const showFeatureCustom =
		isRestrict && config.feature && config.featureMatch === 'custom';
	const warning = warningFor( config );

	return (
		<div className="arraysubs-restriction-fields">
			<ToggleControl
				__nextHasNoMarginBottom
				label={ __( 'Restrict access to this content', 'arraysubs' ) }
				help={ __(
					'When off, everybody can view this content and every setting below is ignored.',
					'arraysubs'
				) }
				checked={ !! config.enabled }
				onChange={ set( 'enabled' ) }
			/>

			{ !! warning && (
				<Notice status="warning" isDismissible={ false }>
					{ warning }
				</Notice>
			) }

			{ !! config.enabled && (
				<Notice status="info" isDismissible={ false }>
					{ __(
						'This restriction takes priority over every Members Access rule. While it is on, any URL rule or content (CPT) rule that also covers this content is skipped for this page — including its archive behavior and its denied action. Overlaps are listed under Members Access → Access-Rule Conflicts.',
						'arraysubs'
					) }
				</Notice>
			) }

			{ !! config.enabled && (
				<>
					<RestrictionSection
						title={ __( 'Restriction Type', 'arraysubs' ) }
						className="arraysubs-restriction-fields__section--restriction-type"
					>
						<SelectControl
							__next40pxDefaultSize
							__nextHasNoMarginBottom
							hideLabelFromVision
							label={ __( 'Restriction Type', 'arraysubs' ) }
							value={ config.mode }
							options={ [
								{
									label: __(
										'Subscription / Role / Purchase (restrict)',
										'arraysubs'
									),
									value: 'restrict',
								},
								{
									label: __(
										'Login state (visibility)',
										'arraysubs'
									),
									value: 'visibility',
								},
							] }
							onChange={ set( 'mode' ) }
						/>
					</RestrictionSection>

					<DeniedSection
						config={ config }
						isRestrict={ isRestrict }
						set={ set }
						update={ update }
					/>

					{ isVisibility && (
						<RestrictionSection
							title={ __( 'Visibility', 'arraysubs' ) }
							className="arraysubs-restriction-fields__section--visibility"
						>
							<SelectControl
								__next40pxDefaultSize
								__nextHasNoMarginBottom
								label={ __( 'Show To', 'arraysubs' ) }
								value={ config.visShow }
								options={ [
									{
										label: __( 'Logged-in users', 'arraysubs' ),
										value: 'logged_in',
									},
									{
										label: __( 'Logged-out users', 'arraysubs' ),
										value: 'logged_out',
									},
								] }
								onChange={ set( 'visShow' ) }
							/>
						</RestrictionSection>
					) }

					{ isRestrict && (
						<RestrictionSection
							className="arraysubs-restriction-fields__section--access-rules"
							title={ __( 'Access Rules', 'arraysubs' ) }
						>
							<StaticTokenSelect
								label={ __( 'Subscription Status', 'arraysubs' ) }
								options={ STATUS_OPTIONS }
								values={ config.status }
								onChange={ set( 'status' ) }
							/>

							<AsyncTokenSelect
								label={ __(
									'Active Subscription To Products',
									'arraysubs'
								) }
								type="products"
								query={ { product_type: 'subscription' } }
								ids={ config.products }
								onChangeIds={ set( 'products' ) }
							/>

							<AsyncTokenSelect
								label={ __(
									'Active Subscription To Variations',
									'arraysubs'
								) }
								type="variations"
								query={ { product_type: 'subscription' } }
								ids={ config.variations }
								onChangeIds={ set( 'variations' ) }
							/>

							<AsyncTokenSelect
								label={ __(
									'Purchased Products (any purchase)',
									'arraysubs'
								) }
								type="products"
								ids={ config.purchased }
								onChangeIds={ set( 'purchased' ) }
							/>

							<StaticTokenSelect
								label={ __( 'User Roles', 'arraysubs' ) }
								options={ ROLE_OPTIONS }
								values={ config.roles }
								onChange={ set( 'roles' ) }
							/>

							<NumberControl
								__next40pxDefaultSize
								label={ __( 'Minimum Lifetime Spend', 'arraysubs' ) }
								min={ 0 }
								step={ 0.01 }
								value={ config.lifetimeSpent }
								onChange={ ( v ) =>
									update( {
										lifetimeSpent: v == null ? '' : String( v ),
									} )
								}
							/>

							<SelectControl
								__next40pxDefaultSize
								__nextHasNoMarginBottom
								label={ __( 'Match Logic', 'arraysubs' ) }
								value={ config.condition }
								options={ [
									{
										label: __(
											'Match ALL of the above (AND)',
											'arraysubs'
										),
										value: 'and',
									},
									{
										label: __(
											'Match ANY of the above (OR)',
											'arraysubs'
										),
										value: 'or',
									},
								] }
								onChange={ set( 'condition' ) }
							/>
						</RestrictionSection>
					) }

					{ isRestrict && (
						<RestrictionSection
							title={ __( 'Plan Feature (Pro)', 'arraysubs' ) }
							className="arraysubs-restriction-fields__section--plan-feature"
						>
							<p className="arraysubs-control-note">
								{ __(
									'Gate by a feature defined on your subscription products (Product → Features, requires ArraySubs Pro). Pick a feature, then choose how to check it. Leave empty to not use a feature rule.',
									'arraysubs'
								) }
							</p>

							<FeatureCombobox
								label={ __( 'Feature', 'arraysubs' ) }
								help={ __(
									'The feature name, exactly as defined on the product.',
									'arraysubs'
								) }
								value={ config.feature }
								onChange={ set( 'feature' ) }
							/>

							{ !! config.feature && (
								<SelectControl
									__next40pxDefaultSize
									__nextHasNoMarginBottom
									label={ __( 'How To Check It', 'arraysubs' ) }
									value={ config.featureMatch }
									help={ __(
										'On/off (toggle) features: use "Has the feature". Numeric features (e.g. seats, API calls): use one of the "at least" options.',
										'arraysubs'
									) }
									options={ [
										{
											label: __(
												'Has the feature (on/off features)',
												'arraysubs'
											),
											value: 'has',
										},
										{
											label: __(
												'Combined amount across their plans is at least…',
												'arraysubs'
											),
											value: 'min_total',
										},
										{
											label: __(
												'At least one plan provides at least…',
												'arraysubs'
											),
											value: 'min_single',
										},
										{
											label: __(
												'Custom comparison (advanced)',
												'arraysubs'
											),
											value: 'custom',
										},
									] }
									onChange={ set( 'featureMatch' ) }
								/>
							) }

							{ showFeatureAmount && (
								<NumberControl
									__next40pxDefaultSize
									label={ __( 'Required Amount', 'arraysubs' ) }
									min={ 0 }
									value={ config.featureValue }
									help={ __(
										'The number the feature must reach.',
										'arraysubs'
									) }
									onChange={ ( v ) =>
										update( {
											featureValue: v == null ? '' : String( v ),
										} )
									}
								/>
							) }

							{ showFeatureCustom && (
								<SelectControl
									__next40pxDefaultSize
									__nextHasNoMarginBottom
									label={ __( 'Comparison', 'arraysubs' ) }
									value={ config.featureOp }
									options={ [
										{ label: __( 'At least (>=)', 'arraysubs' ), value: '>=' },
										{ label: __( 'More than (>)', 'arraysubs' ), value: '>' },
										{ label: __( 'Exactly (=)', 'arraysubs' ), value: '=' },
										{ label: __( 'Not equal (!=)', 'arraysubs' ), value: '!=' },
										{ label: __( 'Less than (<)', 'arraysubs' ), value: '<' },
										{ label: __( 'At most (<=)', 'arraysubs' ), value: '<=' },
									] }
									onChange={ set( 'featureOp' ) }
								/>
							) }

							{ showFeatureCustom && (
								<SelectControl
									__next40pxDefaultSize
									__nextHasNoMarginBottom
									label={ __( 'Combine Multiple Plans By', 'arraysubs' ) }
									value={ config.aggregation }
									help={ __(
										'For presence (on/off) checks use the "Has the feature" mode instead.',
										'arraysubs'
									) }
									options={ [
										{
											label: __( 'Sum — add values across plans', 'arraysubs' ),
											value: 'sum',
										},
										{
											label: __( 'Max — highest single plan', 'arraysubs' ),
											value: 'max',
										},
									] }
									onChange={ set( 'aggregation' ) }
								/>
							) }
						</RestrictionSection>
					) }
				</>
			) }
		</div>
	);
}
