/**
 * Baseline button style properties (WordPress-like direct editing).
 * Variants enable a subset via field_schema `styleSupports`.
 */
import { DEFAULT_BUTTON_ICON_SIZE } from './buttonIcon';

/** @type {readonly string[]} */
export const BUTTON_STYLE_SUPPORT_KEYS = Object.freeze( [
	'colors',
	'fontFamily',
	'size',
	'padding',
	'borderRadius',
	'boxShadow',
	'icon',
] );

/** Full baseline — used when a variant omits styleSupports. */
export const BUTTON_STYLE_SUPPORTS_ALL = [ ...BUTTON_STYLE_SUPPORT_KEYS ];

export const BUTTON_SIZE_PRESETS = Object.freeze( {
	small: { padY: '0.4rem', padX: '0.9rem' },
	medium: { padY: '0.75rem', padX: '1.25rem' },
	large: { padY: '1rem', padX: '1.75rem' },
} );

export const BUTTON_SIZE_OPTIONS = Object.freeze( [
	{ label: 'Small', value: 'small' },
	{ label: 'Medium', value: 'medium' },
	{ label: 'Large', value: 'large' },
	{ label: 'Custom', value: 'custom' },
] );

export const BUTTON_ICON_POSITION_OPTIONS = Object.freeze( [
	{ label: 'Left', value: 'left' },
	{ label: 'Right', value: 'right' },
] );

/**
 * Placement-owned button Design / Style reference keys.
 * When a hero is content-linked to a My Block, label/URL stay on the My Block
 * while these fields still follow the placement (inspector writes them there).
 *
 * @type {readonly string[]}
 */
export const BUTTON_PLACEMENT_STYLE_KEYS = Object.freeze( [
	'styleMode',
	'libraryBlockId',
	'bg',
	'color',
	'fontFamily',
	'fontSize',
	'bgHover',
	'colorHover',
	'size',
	'padY',
	'padX',
	'borderRadius',
	'borderWidth',
	'borderStyle',
	'borderColor',
	'borderWidthMode',
	'borderTopWidth',
	'borderRightWidth',
	'borderBottomWidth',
	'borderLeftWidth',
	'borderTopLeftRadius',
	'borderTopRightRadius',
	'borderBottomRightRadius',
	'borderBottomLeftRadius',
	'shadow',
	'shadowPreset',
	'shadowColor',
	'icon',
	'iconPosition',
	'iconSize',
	'iconColor',
] );

/** CSS var root for collection-button BoxBorderField / BoxRadiusField. */
export const BUTTON_ITEM_BORDER_VAR_ROOT = '--bm-btn-border';
export const BUTTON_ITEM_RADIUS_ALL_VAR = '--bm-btn-radius';
export const BUTTON_ITEM_RADIUS_FIELD_KEY = '--bm-btn-border-radius';

/**
 * Inline border + corner-radius CSS for collection CTA anchors.
 * Falls back to `--bm-btn-radius` when per-corner vars are unset.
 */
export const BUTTON_COLLECTION_BORDER_INLINE_CSS =
	'border-style:var(--bm-btn-border-style, none);' +
	'border-color:var(--bm-btn-border-color, transparent);' +
	'border-top-width:var(--bm-btn-border-top-width, var(--bm-btn-border-width, 0));' +
	'border-right-width:var(--bm-btn-border-right-width, var(--bm-btn-border-width, 0));' +
	'border-bottom-width:var(--bm-btn-border-bottom-width, var(--bm-btn-border-width, 0));' +
	'border-left-width:var(--bm-btn-border-left-width, var(--bm-btn-border-width, 0));' +
	'border-top-left-radius:var(--bm-btn-border-top-left-radius, var(--bm-btn-radius, 8px));' +
	'border-top-right-radius:var(--bm-btn-border-top-right-radius, var(--bm-btn-radius, 8px));' +
	'border-bottom-right-radius:var(--bm-btn-border-bottom-right-radius, var(--bm-btn-radius, 8px));' +
	'border-bottom-left-radius:var(--bm-btn-border-bottom-left-radius, var(--bm-btn-radius, 8px));';

/**
 * Map BoxBorderField / BoxRadiusField CSS var patches → button style props.
 *
 * @type {Readonly<Record<string, string>>}
 */
export const BUTTON_ITEM_BORDER_VAR_TO_PROP = Object.freeze( {
	'--bm-btn-border-width': 'borderWidth',
	'--bm-btn-border-style': 'borderStyle',
	'--bm-btn-border-color': 'borderColor',
	'--bm-btn-border-top-width': 'borderTopWidth',
	'--bm-btn-border-right-width': 'borderRightWidth',
	'--bm-btn-border-bottom-width': 'borderBottomWidth',
	'--bm-btn-border-left-width': 'borderLeftWidth',
	'--bm-btn-border-width-mode': 'borderWidthMode',
	'--bm-btn-radius': 'borderRadius',
	'--bm-btn-border-radius': 'borderRadius',
	'--bm-btn-border-top-left-radius': 'borderTopLeftRadius',
	'--bm-btn-border-top-right-radius': 'borderTopRightRadius',
	'--bm-btn-border-bottom-right-radius': 'borderBottomRightRadius',
	'--bm-btn-border-bottom-left-radius': 'borderBottomLeftRadius',
} );

/**
 * Overlay placement Design / Style reference onto a My Block button item.
 *
 * @param {object} baseItem
 * @param {object} [placementItem]
 * @return {object}
 */
export function overlayButtonPlacementStyles( baseItem, placementItem ) {
	if ( ! placementItem || typeof placementItem !== 'object' ) {
		return baseItem;
	}
	const next = { ...( baseItem && typeof baseItem === 'object' ? baseItem : {} ) };
	BUTTON_PLACEMENT_STYLE_KEYS.forEach( ( key ) => {
		if ( placementItem[ key ] !== undefined ) {
			next[ key ] = placementItem[ key ];
		}
	} );
	return next;
}

/**
 * @param {Array|*} baseList
 * @param {Array|*} [placementList]
 * @return {Array|*}
 */
export function overlayButtonsPlacementStyles( baseList, placementList ) {
	if ( ! Array.isArray( baseList ) ) {
		return Array.isArray( placementList ) ? placementList : baseList;
	}
	if ( ! Array.isArray( placementList ) ) {
		return baseList;
	}
	return baseList.map( ( item, index ) =>
		overlayButtonPlacementStyles( item, placementList[ index ] )
	);
}

/**
 * @param {object} [field] Buttons field from field_schema.
 * @return {string[]}
 */
export function resolveButtonStyleSupports( field = {} ) {
	const raw = field?.styleSupports ?? field?.buttonStyleSupports;
	if ( Array.isArray( raw ) && raw.length ) {
		const allowed = new Set( BUTTON_STYLE_SUPPORT_KEYS );
		return raw.filter( ( key ) => allowed.has( key ) );
	}
	return [ ...BUTTON_STYLE_SUPPORTS_ALL ];
}

/**
 * @param {string[]} supports
 * @param {string} key
 * @return {boolean}
 */
export function buttonSupports( supports, key ) {
	return Array.isArray( supports ) && supports.includes( key );
}

/** Default icon for new hero / slider CTA buttons (namespaced). */
export const DEFAULT_HERO_BUTTON_ICON = 'dashicons:arrow-right-alt';

/**
 * Default style attrs for a new button item (no link).
 *
 * @return {object}
 */
export function defaultButtonStyleAttrs() {
	const pad = BUTTON_SIZE_PRESETS.medium;
	return {
		bg: '#ffffff',
		color: '#3525cd',
		fontFamily: '',
		fontSize: '',
		bgHover: '#f2f3ff',
		colorHover: '#3525cd',
		size: 'medium',
		padY: pad.padY,
		padX: pad.padX,
		borderRadius: '8px',
		borderWidth: '0px',
		borderStyle: 'none',
		borderColor: 'transparent',
		borderWidthMode: 'linked',
		borderTopWidth: '0',
		borderRightWidth: '0',
		borderBottomWidth: '0',
		borderLeftWidth: '0',
		borderTopLeftRadius: '',
		borderTopRightRadius: '',
		borderBottomRightRadius: '',
		borderBottomLeftRadius: '',
		shadow: 'none',
		shadowPreset: 'none',
		shadowColor: 'rgba(0, 0, 0, 0.16)',
		icon: '',
		iconPosition: 'left',
		iconSize: DEFAULT_BUTTON_ICON_SIZE,
		iconColor: '',
	};
}

/**
 * New hero / slider button item (label + icon defaults for Design / Fields).
 *
 * @param {object} [overrides]
 * @return {object}
 */
export function createDefaultHeroButton( overrides = {} ) {
	const { link: linkOverride, ...rest } = overrides;
	const next = {
		...defaultButtonStyleAttrs(),
		icon: DEFAULT_HERO_BUTTON_ICON,
		iconPosition: 'right',
		...rest,
		link: {
			title: 'Get started',
			url: '#',
			opensInNewTab: false,
			...( linkOverride && typeof linkOverride === 'object'
				? linkOverride
				: {} ),
		},
	};
	// Empty icon from field schemas must not wipe the default arrow.
	if ( ! String( next.icon || '' ).trim() ) {
		next.icon = DEFAULT_HERO_BUTTON_ICON;
	}
	if ( ! String( next.iconPosition || '' ).trim() ) {
		next.iconPosition = 'right';
	}
	return next;
}

/**
 * Deep-clone a button and insert it after `index`.
 *
 * @param {Array}  buttons
 * @param {number} index
 * @return {{ next: Array, newIndex: number }|null}
 */
export function duplicateHeroButtonAt( buttons, index ) {
	const list = Array.isArray( buttons ) ? buttons : null;
	const i = Number( index );
	if (
		! list ||
		! Number.isFinite( i ) ||
		i < 0 ||
		i >= list.length ||
		! list[ i ]
	) {
		return null;
	}
	let copy;
	try {
		copy = JSON.parse( JSON.stringify( list[ i ] ) );
	} catch ( e ) {
		return null;
	}
	const next = [ ...list ];
	next.splice( i + 1, 0, copy );
	return { next, newIndex: i + 1 };
}

/**
 * Normalize / migrate a button item’s style props for render + editor.
 *
 * @param {object} item
 * @return {object}
 */
export function normalizeButtonStyleItem( item = {} ) {
	const defaults = defaultButtonStyleAttrs();
	const sizeRaw = String( item.size || '' ).trim();
	const size = BUTTON_SIZE_PRESETS[ sizeRaw ]
		? sizeRaw
		: sizeRaw === 'custom'
		? 'custom'
		: 'medium';

	// Migrate legacy hover-shadow → rest shadow when unset.
	const shadow =
		item.shadow != null && String( item.shadow ).trim() !== ''
			? String( item.shadow )
			: item.shadowHover != null
			? String( item.shadowHover )
			: defaults.shadow;
	const shadowPreset =
		item.shadowPreset != null && String( item.shadowPreset ).trim() !== ''
			? String( item.shadowPreset )
			: item.shadowHoverPreset != null
			? String( item.shadowHoverPreset )
			: defaults.shadowPreset;
	const shadowColor =
		item.shadowColor != null && String( item.shadowColor ).trim() !== ''
			? String( item.shadowColor )
			: item.shadowHoverColor != null
			? String( item.shadowHoverColor )
			: defaults.shadowColor;

	let padY =
		item.padY != null && String( item.padY ).trim() !== ''
			? String( item.padY )
			: '';
	let padX =
		item.padX != null && String( item.padX ).trim() !== ''
			? String( item.padX )
			: '';
	if ( ( ! padY || ! padX ) && size !== 'custom' ) {
		const preset = BUTTON_SIZE_PRESETS[ size ] || BUTTON_SIZE_PRESETS.medium;
		padY = padY || preset.padY;
		padX = padX || preset.padX;
	}
	if ( ! padY ) {
		padY = defaults.padY;
	}
	if ( ! padX ) {
		padX = defaults.padX;
	}

	const styleMode =
		String( item.styleMode || '' ).toLowerCase() === 'library'
			? 'library'
			: 'custom';
	const rawLibId = item.libraryBlockId;
	const parsedLib =
		rawLibId != null && rawLibId !== '' ? Number( rawLibId ) : NaN;
	const libraryBlockId =
		Number.isFinite( parsedLib ) && parsedLib !== 0 ? parsedLib : null;

	return {
		...defaults,
		...item,
		bg: item.bg != null ? String( item.bg ) : defaults.bg,
		color: item.color != null ? String( item.color ) : defaults.color,
		fontFamily:
			item.fontFamily != null ? String( item.fontFamily ) : defaults.fontFamily,
		fontSize:
			item.fontSize != null && String( item.fontSize ).trim() !== ''
				? String( item.fontSize )
				: defaults.fontSize,
		bgHover: item.bgHover != null ? String( item.bgHover ) : defaults.bgHover,
		colorHover:
			item.colorHover != null ? String( item.colorHover ) : defaults.colorHover,
		size,
		padY,
		padX,
		borderRadius:
			item.borderRadius != null && String( item.borderRadius ).trim() !== ''
				? String( item.borderRadius )
				: defaults.borderRadius,
		borderWidth:
			item.borderWidth != null && String( item.borderWidth ).trim() !== ''
				? String( item.borderWidth )
				: defaults.borderWidth,
		borderStyle:
			item.borderStyle != null && String( item.borderStyle ).trim() !== ''
				? String( item.borderStyle )
				: defaults.borderStyle,
		borderColor:
			item.borderColor != null
				? String( item.borderColor )
				: defaults.borderColor,
		borderWidthMode:
			item.borderWidthMode != null &&
			String( item.borderWidthMode ).trim() !== ''
				? String( item.borderWidthMode )
				: defaults.borderWidthMode,
		borderTopWidth:
			item.borderTopWidth != null
				? String( item.borderTopWidth )
				: defaults.borderTopWidth,
		borderRightWidth:
			item.borderRightWidth != null
				? String( item.borderRightWidth )
				: defaults.borderRightWidth,
		borderBottomWidth:
			item.borderBottomWidth != null
				? String( item.borderBottomWidth )
				: defaults.borderBottomWidth,
		borderLeftWidth:
			item.borderLeftWidth != null
				? String( item.borderLeftWidth )
				: defaults.borderLeftWidth,
		borderTopLeftRadius:
			item.borderTopLeftRadius != null
				? String( item.borderTopLeftRadius )
				: defaults.borderTopLeftRadius,
		borderTopRightRadius:
			item.borderTopRightRadius != null
				? String( item.borderTopRightRadius )
				: defaults.borderTopRightRadius,
		borderBottomRightRadius:
			item.borderBottomRightRadius != null
				? String( item.borderBottomRightRadius )
				: defaults.borderBottomRightRadius,
		borderBottomLeftRadius:
			item.borderBottomLeftRadius != null
				? String( item.borderBottomLeftRadius )
				: defaults.borderBottomLeftRadius,
		shadow,
		shadowPreset,
		shadowColor,
		icon: item.icon != null ? String( item.icon ) : '',
		iconPosition:
			String( item.iconPosition || 'left' ).toLowerCase() === 'right'
				? 'right'
				: 'left',
		iconSize: item.iconSize || defaults.iconSize,
		iconColor: item.iconColor != null ? String( item.iconColor ) : '',
		styleMode,
		libraryBlockId,
	};
}

/**
 * CSS-var map for BoxBorderField / BoxRadiusField on a collection button item.
 *
 * @param {object} [styles]
 * @return {Record<string, string>}
 */
export function buttonItemBorderFieldValues( styles = {} ) {
	const s = normalizeButtonStyleItem( styles );
	const values = {
		'--bm-btn-border-width': s.borderWidth,
		'--bm-btn-border-style': s.borderStyle,
		'--bm-btn-border-color': s.borderColor,
		'--bm-btn-border-top-width': s.borderTopWidth,
		'--bm-btn-border-right-width': s.borderRightWidth,
		'--bm-btn-border-bottom-width': s.borderBottomWidth,
		'--bm-btn-border-left-width': s.borderLeftWidth,
		'--bm-btn-border-width-mode': s.borderWidthMode,
		[ BUTTON_ITEM_RADIUS_ALL_VAR ]: s.borderRadius,
	};
	if ( s.borderTopLeftRadius ) {
		values[ '--bm-btn-border-top-left-radius' ] = s.borderTopLeftRadius;
	}
	if ( s.borderTopRightRadius ) {
		values[ '--bm-btn-border-top-right-radius' ] = s.borderTopRightRadius;
	}
	if ( s.borderBottomRightRadius ) {
		values[ '--bm-btn-border-bottom-right-radius' ] =
			s.borderBottomRightRadius;
	}
	if ( s.borderBottomLeftRadius ) {
		values[ '--bm-btn-border-bottom-left-radius' ] =
			s.borderBottomLeftRadius;
	}
	return values;
}

/**
 * Convert a BoxBorderField / BoxRadiusField onChange patch to style props.
 *
 * @param {Record<string, string>} [patch]
 * @return {object}
 */
export function buttonItemStylePatchFromBorderVars( patch = {} ) {
	const out = {};
	Object.entries( patch || {} ).forEach( ( [ varKey, value ] ) => {
		const prop = BUTTON_ITEM_BORDER_VAR_TO_PROP[ varKey ];
		if ( prop ) {
			out[ prop ] = value;
		}
	} );
	return out;
}

/**
 * Escape a CSS custom-property value for an HTML style="" attribute.
 * Mirrors PHP esc_attr so quoted font stacks (e.g. `"Inter", sans-serif`) do
 * not terminate the attribute and drop later `--bm-btn-*` declarations.
 *
 * @param {string|number|null|undefined} value
 * @return {string}
 */
export function escapeStyleAttrCssValue( value ) {
	return String( value ?? '' )
		.replace( /&/g, '&amp;' )
		.replace( /"/g, '&quot;' )
		.replace( /</g, '&lt;' );
}

/**
 * Build inline --bm-btn-* declarations for markup.
 *
 * @param {object} styles From normalizeButtonStyleItem / resolve
 * @return {string}
 */
export function composeButtonInlineStyleVars( styles ) {
	const s = normalizeButtonStyleItem( styles );
	const v = escapeStyleAttrCssValue;
	const parts = [
		`--bm-btn-bg:${ v( s.bg ) }`,
		`--bm-btn-color:${ v( s.color ) }`,
		`--bm-btn-font:${ v( s.fontFamily || 'inherit' ) }`,
		`--bm-btn-font-size:${ v( s.fontSize || '1rem' ) }`,
		`--bm-btn-bg-hover:${ v( s.bgHover ) }`,
		`--bm-btn-color-hover:${ v( s.colorHover ) }`,
		`--bm-btn-pad-y:${ v( s.padY ) }`,
		`--bm-btn-pad-x:${ v( s.padX ) }`,
		`--bm-btn-radius:${ v( s.borderRadius ) }`,
		`--bm-btn-border-width:${ v( s.borderWidth ) }`,
		`--bm-btn-border-style:${ v( s.borderStyle ) }`,
		`--bm-btn-border-color:${ v( s.borderColor ) }`,
		`--bm-btn-border-top-width:${ v( s.borderTopWidth ) }`,
		`--bm-btn-border-right-width:${ v( s.borderRightWidth ) }`,
		`--bm-btn-border-bottom-width:${ v( s.borderBottomWidth ) }`,
		`--bm-btn-border-left-width:${ v( s.borderLeftWidth ) }`,
		`--bm-btn-shadow:${ v( s.shadow || 'none' ) }`,
		// Literal box-shadow so frontend wp_kses / safecss cannot leave only a
		// broken var(--bm-btn-shadow) after stripping rgba() custom props.
		`box-shadow:${ v( s.shadow || 'none' ) }`,
	];
	if ( s.borderTopLeftRadius ) {
		parts.push(
			`--bm-btn-border-top-left-radius:${ v( s.borderTopLeftRadius ) }`
		);
	}
	if ( s.borderTopRightRadius ) {
		parts.push(
			`--bm-btn-border-top-right-radius:${ v( s.borderTopRightRadius ) }`
		);
	}
	if ( s.borderBottomRightRadius ) {
		parts.push(
			`--bm-btn-border-bottom-right-radius:${ v( s.borderBottomRightRadius ) }`
		);
	}
	if ( s.borderBottomLeftRadius ) {
		parts.push(
			`--bm-btn-border-bottom-left-radius:${ v( s.borderBottomLeftRadius ) }`
		);
	}
	return parts.join( ';' );
}
