/**
 * External dependencies.
 */
import { Notice, Button, __experimentalHStack as HStack, __experimentalVStack as VStack, TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';

/**
 * Internal dependencies.
 */
import { useDynamicContent } from '@spectra-pro-extensions/dynamic-content/context/DynamicContentContext';
import CustomSelectControl from '@spectra-pro-components/CustomSelectControl';
import { isEmpty } from '@spectra-pro-helpers';
import LinkPostMetaField from '@spectra-pro-extensions/dynamic-content/components/Fields/LinkPostMetaField';
import LinkAuthorInfoField from '@spectra-pro-extensions/dynamic-content/components/Fields/LinkAuthorInfoField';
import DataSourceField from '@spectra-pro-extensions/dynamic-content/components/Fields/DataSourceField';
import PostSelector from '@spectra-pro-extensions/dynamic-content/components/Fields/SourceField/PostFields/PostSelector';
import ArchiveField from '@spectra-pro-extensions/dynamic-content/components/Fields/SourceField/ArchiveField';
import { getLinkFieldOptions } from '@spectra-pro-extensions/dynamic-content/utils/helpers';

/**
 * Renders a panel for configuring dynamic link settings.
 *
 * Uses the dynamic source format by default with backward compatibility for legacy links.
 * Updates block attributes with the selected dynamic link configuration when applied.
 *
 * @since x.x.x
 *
 * @param {Object}   props                                        - The component props.
 * @param {string}   [props.type='text']                          - The content type ('text' or 'image').
 * @param {Object}   props.attributes                             - The block's attributes.
 * @param {boolean}  props.attributes.spectraProEnableDynamicLink - Whether dynamic link is enabled.
 * @param {Object}   props.attributes.spectraProDynamicLink       - The dynamic link settings.
 * @param {string}   props.attributes.href                        - The current link URL.
 * @param {Function} props.setAttributes                          - Function to update block attributes.
 * @return {Element} The dynamic link configuration panel.
 */
const DynamicLink = ( props ) => {
	const {
		type = 'text',
		attributes: { spectraProEnableDynamicLink, spectraProDynamicLink, href = '', linkURL = '' },
		setAttributes,
	} = props;

	// Access dynamic content context for settings and updates.
	const { settings, updateSetting } = useDynamicContent();

	// State for error messages and loading status
	const [ error, setError ] = useState( null );
	const [ isLoading, setIsLoading ] = useState( false );
	const [ successMessage, setSuccessMessage ] = useState( null );

	// Sync existing dynamic link settings with context when they change.
	useEffect( () => {
		if ( ! spectraProEnableDynamicLink ) {
			return;
		}

		if ( isEmpty( spectraProDynamicLink ) ) {
			// Set default values for new dynamic links
			updateSetting( 'source.type', 'current_post' );
			updateSetting( 'linkField', 'post_permalink' );
			return;
		}

		if ( spectraProDynamicLink.source ) {
			// Sync dynamic format settings
			Object.entries( spectraProDynamicLink ).forEach( ( [ key, val ] ) => {
				if ( key === 'source' ) {
					// Handle nested source settings.
					Object.entries( val ).forEach( ( [ sourceKey, sourceVal ] ) => {
						updateSetting( `source.${ sourceKey }`, sourceVal );
					} );
				} else {
					updateSetting( key, val );
				}
			} );
		}
	}, [ spectraProDynamicLink, spectraProEnableDynamicLink ] );

	// Reset linkField when data source changes to ensure compatibility (but not during initial load)
	useEffect( () => {
		// Don't reset if we're loading existing data
		if ( ! isEmpty( spectraProDynamicLink ) && spectraProDynamicLink.source ) {
			return;
		}

		const currentLinkField = settings.linkField;
		const availableOptions = getLinkFieldOptions( settings.source.type );
		
		// Check if current linkField is still valid for the new data source
		const isCurrentFieldValid = availableOptions.some( option => option.value === currentLinkField );
		
		if ( !isCurrentFieldValid && availableOptions.length > 0 ) {
			// Set to the first available option (usually the default)
			const defaultOption = availableOptions.find( option => option.value !== '' ) || availableOptions[0];
			updateSetting( 'linkField', defaultOption.value );
		}
	}, [ settings.source.type ] );

	/**
	 * Validates the current settings for dynamic link content.
	 *
	 * Ensures required fields are present based on the selected data source.
	 *
	 * @return {boolean} True if settings are valid, false otherwise.
	 */
	const isValid = () => {
		const { source } = settings;

		// Base requirement: type must exist.
		if ( ! source.type ) {
			return false;
		}

		switch ( source.type ) {
			case 'post_type':
				// Must have postId.
				return !! source.postId;

			case 'current_post':
				// Always valid for current post
				return true;

			case 'current_user':
				// If link field is 'custom_field', must have userMetaKey.
				if ( settings.linkField === 'custom_field' ) {
					return (
						!! source.userMetaKey && ( source.userMetaKey !== 'custom' || !! source.user_custom_meta_key )
					);
				}
				return true;

			case 'archive':
				// If link field is 'archive_meta', must have archiveMetaKey.
				if ( settings.linkField === 'archive_meta' ) {
					return !! source.archiveMetaKey;
				}
				return true;

			case 'request_parameter':
				// Must have requestParamKey.
				return !! source.requestParamKey;

			case 'shortcode':
				// Must have shortcodeContent.
				return !! source.shortcodeContent;

			default:
				// For other types (e.g., 'current_post'), just need type.
				return true;
		}
	};

	/**
	 * Applies the dynamic link settings to block attributes.
	 *
	 * Constructs a formatted data object from the current settings and updates the
	 * block's attributes with the dynamic link configuration.
	 */
	const handleApply = async () => {
		if ( ! isValid() ) return;

		setIsLoading( true );
		setError( null );
		setSuccessMessage( null );
		
		try {
			// Dynamic source format
			const formatData = {
				type: 'link',
				source: {
					type: settings.source.type,
				},
				linkField: settings.linkField || 'post_permalink',
			};

			// Helper to set properties if they exist.
			const setIfExists = ( target, key, val ) => {
				if ( val !== undefined && val !== '' ) target[ key ] = val;
			};

			// Source-specific configurations.
			const sourceHandlers = {
				post_type: () => setIfExists( formatData.source, 'postId', settings.source.postId ),
				current_user: () => {
					if ( settings.linkField === 'custom_field' ) {
						setIfExists( formatData.source, 'userMetaKey', settings.source.userMetaKey );
					}
				},
				request_parameter: () =>
					setIfExists( formatData.source, 'requestParamKey', settings.source.requestParamKey ),
				shortcode: () =>
					setIfExists( formatData.source, 'shortcodeContent', settings.source.shortcodeContent ),
				archive: () => {
					if ( settings.linkField === 'archive_meta' ) {
						setIfExists( formatData.source, 'archiveMetaKey', settings.source.archiveMetaKey );
					}
				},
			};

			// Link field-specific configurations.
			const linkFieldHandlers = {
				custom_field: () => {
					setIfExists( formatData.source, 'postCustomField', settings.source.postCustomField );
					if ( settings.source.postCustomField === 'custom' ) {
						setIfExists( formatData.source, 'postMetaKey', settings.source.postMetaKey );
					}
				},
				author_archive: () => {
					setIfExists( formatData.source, 'authorField', settings.source.authorField );
					if ( settings.source.authorField === 'custom' ) {
						setIfExists( formatData.source, 'authorMetaKey', settings.source.authorMetaKey );
					}
				},
				author_website: () => {
					setIfExists( formatData.source, 'authorField', settings.source.authorField );
					if ( settings.source.authorField === 'custom' ) {
						setIfExists( formatData.source, 'authorMetaKey', settings.source.authorMetaKey );
					}
				},
			};

			// Apply source and link field-specific settings.
			sourceHandlers[ settings.source.type ]?.();
			linkFieldHandlers[ settings.linkField ]?.();

			// Update block attributes with dynamic link settings.
			setAttributes( { spectraProDynamicLink: formatData } );

			// Update block attributes with link URL.
			if ( ! href && 'image' === type ) {
				setAttributes( { href: 'spectra-dynamic-link' } );
			}

			if ( ! linkURL && 'text' === type ) {
				setAttributes( { linkURL: 'spectra-dynamic-link' } );
			}

			// Show success message
			setSuccessMessage( __( 'Dynamic link updated successfully!', 'spectra-pro' ) );
			
			// Auto-dismiss after 3 seconds
			setTimeout( () => {
				setSuccessMessage( null );
			}, 3000 );
			
		} catch ( e ) {
			setError( __( 'Failed to apply dynamic link. Please try again.', 'spectra-pro' ) );
		} finally {
			setIsLoading( false );
		}
	};

	/**
	 * Determines the label for the apply/update button based on type and state.
	 *
	 * @return {string} The button label ('Add Link', 'Update Link', 'Apply', or 'Update').
	 */
	const getButtonLabel = () => {
		// Show loading label when processing
		if ( isLoading ) {
			return isEmpty( spectraProDynamicLink ) 
				? __( 'Applying…', 'spectra-pro' )
				: __( 'Updating…', 'spectra-pro' );
		}
		
		// Default labels
		if ( type === 'image' ) {
			return isEmpty( spectraProDynamicLink )
				? __( 'Add Link', 'spectra-pro' )
				: __( 'Update Link', 'spectra-pro' );
		}

		return isEmpty( spectraProDynamicLink ) ? __( 'Apply', 'spectra-pro' ) : __( 'Update', 'spectra-pro' );
	};

	return (
		<>
			{ error && (
				<Notice status="error" isDismissible onDismiss={ () => setError( null ) }>
					{ error }
				</Notice>
			) }

			{ successMessage && (
				<Notice status="success" isDismissible onDismiss={ () => setSuccessMessage( null ) }>
					{ successMessage }
				</Notice>
			) }

			{ spectraProEnableDynamicLink && (
				<VStack spacing={ 4 }>
					{ /* Data Source Selection */ }
					<DataSourceField settings={ settings } updateSetting={ updateSetting } />
					
					{ /* Post Selector for Post Type */ }
					{ settings.source.type === 'post_type' && (
						<PostSelector settings={ settings } updateSetting={ updateSetting } />
					) }
					
					{ /* Request Parameter Key Field */ }
					{ settings.source.type === 'request_parameter' && (
						<TextControl
							label={ __( 'Request Parameter Key', 'spectra-pro' ) }
							help={ __( 'Enter the name of the URL parameter to extract (e.g., "category", "search_term")', 'spectra-pro' ) }
							value={ settings.source.requestParamKey || '' }
							onChange={ ( newValue ) => updateSetting( 'source.requestParamKey', newValue ) }
							placeholder={ __( 'Parameter name', 'spectra-pro' ) }
						/>
					) }

					{ /* Shortcode Content Field */ }
					{ settings.source.type === 'shortcode' && (
						<TextControl
							label={ __( 'Shortcode Content', 'spectra-pro' ) }
							help={ __( 'Enter the shortcode that outputs a URL (e.g., "[my_url_shortcode]")', 'spectra-pro' ) }
							value={ settings.source.shortcodeContent || '' }
							onChange={ ( newValue ) => updateSetting( 'source.shortcodeContent', newValue ) }
							placeholder={ __( '[shortcode]', 'spectra-pro' ) }
						/>
					) }
					
					{ /* Link Field Selection */ }
					<CustomSelectControl
						label={ __( 'Link Field', 'spectra-pro' ) }
						value={ settings.linkField || '' }
						options={ getLinkFieldOptions( settings.source.type ) }
						onChange={ ( newValue ) => updateSetting( 'linkField', newValue ) }
					/>
					
					{ /* Additional fields for specific link field types */ }
					{ settings.linkField === 'custom_field' && ( settings.source.type === 'current_post' || settings.source.type === 'post_type' ) && (
						<LinkPostMetaField settings={ settings } updateSetting={ updateSetting } type="url" />
					) }
					
					{ ( settings.linkField === 'author_archive' || settings.linkField === 'author_website' ) && settings.source.type === 'current_post' && (
						<LinkAuthorInfoField settings={ settings } updateSetting={ updateSetting } type="url" />
					) }
					
					{ /* Archive Custom Field Meta Key Selection */ }
					{ settings.linkField === 'archive_meta' && settings.source.type === 'archive' && (
						<ArchiveField settings={ settings } updateSetting={ updateSetting } type="url" />
					) }
				</VStack>
			) }

			{ /* Footer Buttons */ }
			<HStack justify="end">
				<Button 
					variant="primary"
					onClick={ handleApply } 
					isBusy={ isLoading } 
					disabled={ ! isValid() || isLoading }
				>
					{ getButtonLabel() }
				</Button>
			</HStack>
		</>
	);
};

export default DynamicLink;
