import { Controller } from 'react-hook-form';
import TextField from '../Fields/TextField';
import HiddenField from '../Fields/HiddenField';
import ErrorBoundary from '@/components/Common/ErrorBoundary';
import { __, sprintf } from '@wordpress/i18n';
import { memo } from 'react';
import TextAreaField from './TextAreaField';
import IpBlockField from './IpBlockField';
import SwitchField from './SwitchField';
import ButtonControlField from './ButtonControlField';
import EmailReportsField from './EmailReportsField';
import CheckboxGroupField from './CheckboxGroupField';
import GoalsSettings from '../Goals/GoalsSettings';
import LicenseField from './LicenseField';
import SelectField from './SelectField';
import NumberField from './NumberField';
import LogoEditorField from './LogoEditorField';
import RestoreArchivesField from './RestoreArchivesField';
import RadioField from './RadioField';
import UploadField from './UploadField';
import ExportSettingsField from './ExportSettingsField';
import useLicenseData from '@/hooks/useLicenseData';

const fieldComponents = {
	text: TextField,
	number: NumberField,
	api: HiddenField,
	hidden: HiddenField,
	checkbox: SwitchField,
	textarea: TextAreaField,
	ip_blocklist: IpBlockField,
	button: ButtonControlField,
	email_reports: EmailReportsField,
	checkbox_group: CheckboxGroupField,
	goals: GoalsSettings,
	license: LicenseField,
	select: SelectField,
	logo_editor: LogoEditorField,
	restore_archives: RestoreArchivesField,
	radio: RadioField,
	upload: UploadField,
	export_settings: ExportSettingsField
};

const Field = memo( ({ setting, control, ...props }) => {
	const { isLicenseValid } = useLicenseData();

	// Special handling for goal(s) type that should not be wrapped in a controller.
	if ( 'goals' === setting.type ) {
		return (
			<ErrorBoundary>
				<GoalsSettings />
			</ErrorBoundary>
		);
	}

	const FieldComponent = fieldComponents[setting.type];

	if ( ! FieldComponent ) {
		return (
			<div className="w-full">
				Unknown field type: {setting.type} {setting.id}
			</div>
		);
	}

	// Custom validation for IP blocklist field
	// IPv4 + IPv6 validation + duplicate detection
	const getCustomValidation = () => {
		if ( 'ip_blocklist' === setting.type ) {

			// Strict IPv4
			const ipv4Regex =
				/^((25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(25[0-5]|2[0-4]\d|1?\d{1,2})$/;

			// IPv6 (full, compressed, leading ::, trailing ::, and IPv4-mapped)
			// Note: This is intentionally broad but practical for UI validation.
			const ipv6Regex =
				/^((?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,7}:|:(?::[0-9A-Fa-f]{1,4}){1,7}|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?:(?::[0-9A-Fa-f]{1,4}){1,6})|::(?:ffff(?::0{1,4})?:)?(?:(25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(25[0-5]|2[0-4]\d|1?\d{1,2}))$/;

			// Helper: is valid IP (v4 or v6)
			const isValidIp = ( ip ) => ipv4Regex.test( ip ) || ipv6Regex.test( ip );

			// Helper: normalize list input to clean lines
			const toLines = ( value ) =>
				value
					.replace( /\r\n/g, '\n' )
					.replace( /\r/g, '\n' )
					.split( '\n' )
					.map( ( s ) => s.trim() )
					.filter( ( s ) => '' !== s );

			// Helper: key for duplicate detection (case-insensitive for IPv6)
			const dupKey = ( ip ) => ip.toLowerCase();

			return {
				validate: {

					// Validate each line is IPv4 or IPv6
					validIps: ( value ) => {
						if ( ! value ) {
							return true;
						}

						const lines = toLines( value );

						if ( 0 === lines.length ) {
							return true;
						}

						const invalid = lines.filter( ( ip ) => ! isValidIp( ip ) );

						// Return true or an error string (react-hook-form compatible)
						return (
							0 === invalid.length ||
							__(
								'Invalid IP address format:',
								'burst-statistics'
							) + invalid.join( ', ' )
						);
					},

					// Check duplicates (case-insensitive to avoid IPv6 casing dupes)
					noDuplicates: ( value ) => {
						if ( ! value ) {
							return true;
						}

						const lines = toLines( value );
						if ( 0 === lines.length ) {
							return true;
						}

						/** @type {Record<string, number>} */
						const counts = {};
						lines.forEach( ( ip ) => {
							const key = dupKey( ip );
							counts[key] = ( counts[key] || 0 ) + 1;
						});

						const dups = Object.entries( counts )
							.filter( ([ , n ]) => 1 < n )
							.map( ([ k ]) => k );

						return (
							0 === dups.length ||
							__(
								'Duplicate IP addresses found:',
								'burst-statistics'
							) + dups.join( ', ' )
						);
					}
				}
			};
		}

		// Fallback to existing validation if present
		return setting.validation?.validate ?
			{ validate: setting.validation.validate } :
			{};
	};

	const validationRules = {
		...( setting.required && {
			required: {
				value: true,
				message:
					setting.requiredMessage ||
					__( 'This field is required', 'burst-statistics' )
			}
		}),
		...( setting.validation?.regex && {
			pattern: {

				// hardcoded regex, no user input used.
				value: new RegExp( setting.validation.regex ), // nosemgrep
				message:
					setting.validation.message ||
					__( 'Invalid format', 'burst-statistics' )
			}
		}),
		...getCustomValidation(),
		...( 'number' === setting.type &&
			setting.min !== undefined && {
				min: {
					value: setting.min,
					message: sprintf(
						__( 'Value must be at least %s', 'burst-statistics' ),
						setting.min
					)
				}
			}),
		...( 'number' === setting.type &&
			setting.max !== undefined && {
				max: {
					value: setting.max,
					message: sprintf(
						__( 'Value must be at most %s', 'burst-statistics' ),
						setting.max
					)
				}
			}),
		...( setting.minLength && { minLength: setting.minLength }),
		...( setting.maxLength && { maxLength: setting.maxLength })
	};

	const conditionallyDisabled =
		setting.disabled ||
		( setting.pro && ! isLicenseValid ) ||
		props.settingsIsUpdating;

	return (
		<ErrorBoundary>
			<Controller
				name={setting.id}
				control={control}
				rules={validationRules}
				defaultValue={setting.value || setting.default}
				render={({ field, fieldState }) => (
					<FieldComponent
						field={field}
						fieldState={fieldState}
						control={control}
						required={setting.required}
						label={setting.label || setting.id}
						disabled={conditionallyDisabled}
						context={setting.context}
						help={setting.help}
						options={setting.options}
						setting={setting}
						recommended={setting.recommended}
						pro={setting.pro}
						{...props}
					/>
				)}
			/>
		</ErrorBoundary>
	);
});

Field.displayName = 'Field';

export default Field;
