import React, { cloneElement, forwardRef, isValidElement, useId } from 'react';
import { __ } from '@wordpress/i18n';
import Icon from '../icons/Icon';

/**
 * Field wrapper: label, control, hint and inline error, wired together with
 * ids/aria attributes. The control is the single child element; it receives
 * id, aria-invalid, aria-describedby and aria-required automatically.
 */
export function Field({ label, hint, error, required = false, optional = false, id: idProp, className = '', children, hideLabel = false }) {
	const autoId = useId();
	const id = idProp || `bp-f-${autoId.replace(/:/g, '')}`;
	const hintId = hint ? `${id}-hint` : undefined;
	const errorId = error ? `${id}-error` : undefined;
	const describedBy = [hintId, errorId].filter(Boolean).join(' ') || undefined;

	const control = isValidElement(children)
		? cloneElement(children, {
				id: children.props.id || id,
				'aria-invalid': error ? 'true' : children.props['aria-invalid'],
				'aria-describedby': [children.props['aria-describedby'], describedBy].filter(Boolean).join(' ') || undefined,
				'aria-required': required ? 'true' : children.props['aria-required'],
		  })
		: children;

	return (
		<div className={['bp-field', error ? 'is-invalid' : '', className].filter(Boolean).join(' ')}>
			{label ? (
				<label className={['bp-label', hideLabel ? 'bp-visually-hidden' : ''].filter(Boolean).join(' ')} htmlFor={id}>
					{label}
					{required ? (
						<span className="bp-label__req" aria-hidden="true">
							*
						</span>
					) : null}
					{optional && !required ? <span className="bp-label__optional">{__('(optional)', 'pointly-booking')}</span> : null}
				</label>
			) : null}
			{control}
			{hint ? (
				<div id={hintId} className="bp-hint">
					{hint}
				</div>
			) : null}
			{error ? (
				<div id={errorId} className="bp-error-text" role="alert">
					<Icon name="alert-circle" size={14} />
					<span>{error}</span>
				</div>
			) : null}
		</div>
	);
}

export const Input = forwardRef(function Input({ size = 'md', icon, className = '', end, ...rest }, ref) {
	// Emails, phone numbers and URLs are always written left-to-right.
	const ltrTypes = ['email', 'tel', 'url'];
	const dir = rest.dir || (ltrTypes.includes(rest.type) ? 'ltr' : undefined);
	const input = (
		<input ref={ref} dir={dir} className={['bp-input', size === 'sm' ? 'bp-input--sm' : '', className].filter(Boolean).join(' ')} {...rest} />
	);
	if (!icon && !end) return input;
	return (
		<div className="bp-input-wrap">
			{icon ? <Icon name={icon} className="bp-input-wrap__icon" /> : null}
			{input}
			{end ? <div className="bp-input-wrap__end">{end}</div> : null}
		</div>
	);
});

export const Textarea = forwardRef(function Textarea({ className = '', rows = 4, ...rest }, ref) {
	return <textarea ref={ref} rows={rows} className={['bp-textarea', className].filter(Boolean).join(' ')} {...rest} />;
});

/**
 * Native select. `options` = [{value, label, disabled}] or children.
 */
export const Select = forwardRef(function Select({ options, placeholder, size = 'md', className = '', children, ...rest }, ref) {
	return (
		<select ref={ref} className={['bp-select', size === 'sm' ? 'bp-select--sm' : '', className].filter(Boolean).join(' ')} {...rest}>
			{placeholder != null ? <option value="">{placeholder}</option> : null}
			{Array.isArray(options)
				? options.map((o) => (
						<option key={String(o.value)} value={o.value} disabled={o.disabled}>
							{o.label}
						</option>
				  ))
				: children}
		</select>
	);
});

export const Checkbox = forwardRef(function Checkbox({ label, description, className = '', id: idProp, ...rest }, ref) {
	const autoId = useId();
	const id = idProp || `bp-cb-${autoId.replace(/:/g, '')}`;
	return (
		<label className={['bp-check', className].filter(Boolean).join(' ')} htmlFor={id}>
			<input ref={ref} id={id} type="checkbox" className="bp-check__input" {...rest} />
			{label != null ? (
				<span className="bp-check__text">
					{label}
					{description ? <span className="bp-check__desc">{description}</span> : null}
				</span>
			) : null}
		</label>
	);
});

/**
 * Radio group rendered as a fieldset with a legend.
 * options = [{value, label, description, disabled}]
 */
export function RadioGroup({ legend, name, value, onChange, options = [], inline = false, hideLegend = false, error }) {
	const autoId = useId();
	const groupName = name || `bp-rg-${autoId.replace(/:/g, '')}`;
	const errorId = error ? `${groupName}-error` : undefined;
	return (
		<fieldset
			className={['bp-radio-group', inline ? 'bp-radio-group--inline' : ''].filter(Boolean).join(' ')}
			aria-describedby={errorId}
		>
			{legend ? <legend className={['bp-label', hideLegend ? 'bp-visually-hidden' : ''].filter(Boolean).join(' ')}>{legend}</legend> : null}
			{options.map((o) => {
				const id = `${groupName}-${String(o.value).replace(/[^\w-]/g, '_')}`;
				return (
					<label key={String(o.value)} className="bp-check" htmlFor={id}>
						<input
							id={id}
							type="radio"
							className="bp-check__input"
							name={groupName}
							value={o.value}
							checked={String(value) === String(o.value)}
							disabled={o.disabled}
							aria-invalid={error ? 'true' : undefined}
							onChange={() => onChange && onChange(o.value)}
						/>
						<span className="bp-check__text">
							{o.label}
							{o.description ? <span className="bp-check__desc">{o.description}</span> : null}
						</span>
					</label>
				);
			})}
			{error ? (
				<div id={errorId} className="bp-error-text" role="alert">
					<Icon name="alert-circle" size={14} />
					<span>{error}</span>
				</div>
			) : null}
		</fieldset>
	);
}

/**
 * Toggle switch (role="switch").
 */
export const Switch = forwardRef(function Switch({ checked = false, onChange, label, description, disabled = false, className = '', id, ...rest }, ref) {
	return (
		<button
			ref={ref}
			id={id}
			type="button"
			role="switch"
			aria-checked={checked ? 'true' : 'false'}
			disabled={disabled}
			className={['bp-switch', className].filter(Boolean).join(' ')}
			onClick={() => onChange && onChange(!checked)}
			{...rest}
		>
			<span className="bp-switch__track" aria-hidden="true">
				<span className="bp-switch__thumb" />
			</span>
			{label != null ? (
				<span>
					<span className="bp-switch__label">{label}</span>
					{description ? <span className="bp-switch__desc">{description}</span> : null}
				</span>
			) : null}
		</button>
	);
});
