/**
 * Per-slide Layout styles for hero slider (mirrors single-hero Layout controls).
 */

import { __ } from '@wordpress/i18n';
import {
	CONTENT_ALIGN_VARS,
	CONTAINER_ALIGN_VARS,
	isStyleFieldVisibleAtBreakpoint,
} from '../styleFieldDefaults';
import {
	effective,
	hasAny,
	merge,
	normalize,
	toCss,
	toCssForBreakpoint,
} from '../cssVars';

/** Keys owned per slide (not block General). */
export const SLIDE_LAYOUT_VAR_KEYS = [
	'--bm-bg',
	'--bm-bg-image',
	'--bm-bg-gradient',
	'--bm-bg-gradient-last',
	'--bm-overlay',
	'--bm-content-align',
	'--bm-text-align',
	'--bm-align-items',
	'--bm-justify-content',
	'--bm-container-align',
	'--bm-inner-margin',
	'--bm-media-margin-inline-start',
	'--bm-media-margin-inline-end',
	'--bm-content-max-width',
	'--bm-min-height',
	'--bm-columns-breakpoint',
	'--bm-columns-stack-order',
	'--bm-media-frame',
	// Container Spacing
	'--bm-padding',
	'--bm-padding-y',
	'--bm-padding-x',
	'--bm-padding-top',
	'--bm-padding-right',
	'--bm-padding-bottom',
	'--bm-padding-left',
	'--bm-margin',
	'--bm-margin-y',
	'--bm-margin-x',
	'--bm-margin-top',
	'--bm-margin-right',
	'--bm-margin-bottom',
	'--bm-margin-left',
	// Elements Spacing
	'--bm-gap',
	'--bm-columns-gap',
];

/**
 * Style schema groups for Design → Slides → specific slide
 * (Layout + Container Spacing + Elements Spacing).
 */
export const SLIDE_LAYOUT_STYLE_SCHEMA = [
	{
		group: __( 'Background', 'joc-blockora-morph' ),
		fields: [
			{ key: '--bm-bg', label: __( 'Background Color', 'joc-blockora-morph' ), type: 'color', enableGradient: true },
			{ key: '--bm-bg-image', label: __( 'Image Background', 'joc-blockora-morph' ), type: 'imageBackground' },
			{ key: '--bm-overlay', label: __( 'Overlay Background', 'joc-blockora-morph' ), type: 'overlay', enableGradient: true },
		],
	},
	{
		
		group: __( 'Layout', 'joc-blockora-morph' ),
		fields: [
			{
				key: '--bm-container-align',
				label: __( 'Container alignment', 'joc-blockora-morph' ),
				type: 'containerAlign',
				default: 'center',
				help: __(
					'Position the content container left, center, or right within the section. Set separately for Desktop, Tablet, and Mobile.',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-content-align',
				label: __( 'Content alignment', 'joc-blockora-morph' ),
				type: 'contentAlign',
				default: 'left',
				help: __(
					'Align text and media inside the content stack left, center, or right. Does not move the container. Set separately for Desktop, Tablet, and Mobile.',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-content-max-width',
				label: __( 'Content max width', 'joc-blockora-morph' ),
				type: 'contentMaxWidth',
				help: __(
					'How wide the content inside this slide can stretch. Choose Full width to use the whole section.',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-min-height',
				label: __( 'Min height', 'joc-blockora-morph' ),
				type: 'minHeight',
				help: __(
					'Minimum height of this hero slide. Choose None to size to content, or set a custom value with units.',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-columns-breakpoint',
				label: __( 'Stack columns below', 'joc-blockora-morph' ),
				type: 'columnsBreakpoint',
				shared: true,
				columnsOnly: true,
				help: __(
					'One setting for all viewports. Below this screen width, image-left / image-right slides stack into one column.',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-columns-stack-order',
				label: __( 'Reverse stacked order', 'joc-blockora-morph' ),
				type: 'columnsStackOrder',
				shared: true,
				columnsOnly: true,
				help: __(
					'One setting for all viewports. When columns stack, swap the image and text so they appear in the opposite order.',
					'joc-blockora-morph'
				),
			},
		],
	},
	{
		group: __( 'Container Spacing', 'joc-blockora-morph' ),
		fields: [
			{
				key: '--bm-padding',
				label: __( 'Padding', 'joc-blockora-morph' ),
				type: 'boxSpacing',
				verticalKey: '--bm-padding-y',
				horizontalKey: '--bm-padding-x',
			},
			{
				key: '--bm-margin',
				label: __( 'Margin', 'joc-blockora-morph' ),
				type: 'boxSpacing',
				verticalKey: '--bm-margin-y',
				horizontalKey: '--bm-margin-x',
			},
		],
	},
	{
		group: __( 'Elements Spacing', 'joc-blockora-morph' ),
		fields: [
			{
				key: '--bm-gap',
				label: __( 'Content gap', 'joc-blockora-morph' ),
				type: 'spacing',
				help: __(
					'Space between elements in the content stack (badge, heading, CTA, etc.).',
					'joc-blockora-morph'
				),
			},
			{
				key: '--bm-columns-gap',
				label: __( 'Columns gap', 'joc-blockora-morph' ),
				type: 'spacing',
				columnsOnly: true,
				help: __(
					'Space between the image column and the content column on column layouts.',
					'joc-blockora-morph'
				),
			},
		],
	},
];

/** General-tab style groups that belong per-slide instead. */
export const SLIDE_LEVEL_STYLE_GROUP_NAMES = [
	'background',
	'layout',
	'container spacing',
	'elements spacing',
];

/**
 * @param {string} groupName
 * @return {boolean}
 */
export function isSlideLevelStyleGroup( groupName ) {
	return SLIDE_LEVEL_STYLE_GROUP_NAMES.includes(
		String( groupName || '' ).toLowerCase()
	);
}
/**
 * @param {string} layout
 * @return {boolean}
 */
export function isColumnsSlideLayout( layout ) {
	const key = String( layout || 'simple' ).toLowerCase();
	return key === 'image-left' || key === 'image-right';
}

/**
 * Column media hide/show is only offered on tablet & mobile (desktop keeps the column).
 *
 * @param {boolean} isColumns
 * @return {Record<string, string[]>|null}
 */
export function columnMediaVisibilityKeyBreakpoints( isColumns ) {
	return isColumns ? { image: [ 'tablet', 'mobile' ] } : null;
}

/**
 * Fullscreen media frame is for image/video fills — not oEmbed/iframe.
 *
 * @param {unknown} media
 * @return {boolean}
 */
export function mediaAllowsFullscreenFrame( media ) {
	const kind = String(
		media && typeof media === 'object' ? media.type || 'image' : 'image'
	).toLowerCase();
	return kind === 'image' || kind === 'video' || kind === '';
}

/**
 * Default Layout cssVars for a new slide (aligned with single-hero variants).
 *
 * @param {string} [layout]
 * @return {{ desktop: Record<string, string>, tablet: object, mobile: object }}
 */
export function defaultSlideLayoutCssVars( layout = 'simple' ) {
	const key = String( layout || 'simple' ).toLowerCase();
	const columns = isColumnsSlideLayout( key );
	const contentAlign = columns ? 'left' : 'center';
	const contentPatch = CONTENT_ALIGN_VARS[ contentAlign ] || CONTENT_ALIGN_VARS.center;
	// Columns grids were always centered; stacked heroes match content default.
	const containerPatch = CONTAINER_ALIGN_VARS.center;
	const desktop = {
		...contentPatch,
		...containerPatch,
		'--bm-content-max-width': columns ? '72rem' : '48rem',
		'--bm-min-height': '28rem',
	};
	if ( columns ) {
		desktop[ '--bm-columns-breakpoint' ] = '1024px';
		desktop[ '--bm-columns-stack-order' ] = 'default';
		desktop[ '--bm-media-frame' ] = 'framed';
	}
	return normalize( desktop );
}

/**
 * Pick Layout keys from a responsive cssVars map.
 *
 * @param {object} vars
 * @return {object}
 */
export function pickSlideLayoutVars( vars ) {
	const n = normalize( vars );
	const out = { desktop: {}, tablet: {}, mobile: {} };
	[ 'desktop', 'tablet', 'mobile' ].forEach( ( bp ) => {
		SLIDE_LAYOUT_VAR_KEYS.forEach( ( key ) => {
			if (
				Object.prototype.hasOwnProperty.call( n[ bp ] || {}, key ) &&
				String( n[ bp ][ key ] ?? '' ).trim() !== ''
			) {
				out[ bp ][ key ] = n[ bp ][ key ];
			}
		} );
	} );
	return backfillSlideJustifyContent( out );
}

/**
 * Ensure --bm-justify-content exists when Content alignment vars are present.
 *
 * @param {object} vars
 * @return {object}
 */
function backfillSlideJustifyContent( vars ) {
	const n = normalize( vars );
	[ 'desktop', 'tablet', 'mobile' ].forEach( ( bp ) => {
		const map = { ...( n[ bp ] || {} ) };
		if ( String( map[ '--bm-justify-content' ] ?? '' ).trim() ) {
			return;
		}
		const align = String( map[ '--bm-content-align' ] ?? '' ).trim();
		if ( align && CONTENT_ALIGN_VARS[ align ] ) {
			map[ '--bm-justify-content' ] =
				CONTENT_ALIGN_VARS[ align ][ '--bm-justify-content' ];
			n[ bp ] = map;
			return;
		}
		const items = String( map[ '--bm-align-items' ] ?? '' ).trim();
		if ( items ) {
			map[ '--bm-justify-content' ] = items;
			n[ bp ] = map;
		}
	} );
	return n;
}

/**
 * Effective Layout vars for a slide: own cssVars, else block Layout fallback, else defaults.
 * When the slide already has cssVars, missing keys (e.g. spacing still on the block) are filled from the block.
 *
 * @param {object} slide
 * @param {object} [blockCssVars]
 * @return {object}
 */
export function resolveSlideLayoutCssVars( slide, blockCssVars = {} ) {
	const own = normalize( slide?.cssVars || {} );
	const fromBlock = pickSlideLayoutVars( blockCssVars );
	if ( hasAny( own ) ) {
		return backfillSlideJustifyContent( merge( fromBlock, own ) );
	}
	if ( hasAny( fromBlock ) ) {
		return backfillSlideJustifyContent( fromBlock );
	}
	return defaultSlideLayoutCssVars( slide?.layout );
}

/**
 * Ensure slide has cssVars (hydrate from block / defaults on first edit).
 *
 * @param {object} slide
 * @param {object} [blockCssVars]
 * @return {object}
 */
export function ensureSlideLayoutCssVars( slide, blockCssVars = {} ) {
	return resolveSlideLayoutCssVars( slide, blockCssVars );
}

/**
 * Filter slide style fields for layout + breakpoint.
 *
 * @param {Array<object>} fields
 * @param {string} layout
 * @param {string} breakpoint
 * @return {Array<object>}
 */
function filterSlideStyleFields( fields, layout, breakpoint = 'desktop' ) {
	const columns = isColumnsSlideLayout( layout );
	return ( fields || [] ).filter( ( field ) => {
		if ( field.columnsOnly && ! columns ) {
			return false;
		}
		return isStyleFieldVisibleAtBreakpoint( field, breakpoint );
	} );
}

/**
 * Flat list of slide style fields (Layout + spacing) for this layout.
 *
 * @param {string} layout
 * @param {string} breakpoint
 * @return {Array<object>}
 */
export function slideLayoutFieldsFor( layout, breakpoint = 'desktop' ) {
	return SLIDE_LAYOUT_STYLE_SCHEMA.flatMap( ( group ) =>
		filterSlideStyleFields( group.fields, layout, breakpoint )
	);
}

/**
 * Grouped slide style schema (Layout, Container Spacing, Elements Spacing).
 *
 * @param {string} layout
 * @param {string} breakpoint
 * @return {Array<{ group: string, fields: Array<object> }>}
 */
export function slideStyleGroupsFor( layout, breakpoint = 'desktop' ) {
	return SLIDE_LAYOUT_STYLE_SCHEMA.map( ( group ) => ( {
		group: group.group,
		fields: filterSlideStyleFields( group.fields, layout, breakpoint ),
	} ) ).filter( ( group ) => group.fields.length > 0 );
}
/**
 * CSS selector for one slide inside a block.
 *
 * @param {string} blockSelector
 * @param {number} index
 * @return {string}
 */
export function slideCssSelector( blockSelector, index ) {
	return `${ blockSelector } [data-bm-slide-index="${ Number( index ) }"]`;
}

/**
 * Emit Layout CSS for all slides.
 *
 * @param {string} blockSelector
 * @param {Array} slides
 * @param {object} [blockCssVars] Fallback when slide has no cssVars
 * @param {string|null} [breakpoint] When set, bake one breakpoint (editor preview)
 * @return {string}
 */
export function toCssForSlides(
	blockSelector,
	slides = [],
	blockCssVars = {},
	breakpoint = null
) {
	if ( ! blockSelector || ! Array.isArray( slides ) || ! slides.length ) {
		return '';
	}
	const parts = [];
	slides.forEach( ( slide, index ) => {
		const vars = resolveSlideLayoutCssVars( slide, blockCssVars );
		if ( ! hasAny( vars ) ) {
			return;
		}
		const sel = slideCssSelector( blockSelector, index );
		const css =
			breakpoint && [ 'desktop', 'tablet', 'mobile' ].includes( breakpoint )
				? toCssForBreakpoint( sel, vars, breakpoint )
				: toCss( sel, vars );
		if ( css && css.trim() ) {
			parts.push( css );
		}
	} );
	return parts.join( '\n\n' );
}

/**
 * Effective flat Layout values for StyleFieldList (active breakpoint).
 *
 * @param {object} slide
 * @param {object} blockCssVars
 * @param {string} breakpoint
 * @return {Record<string, string>}
 */
export function effectiveSlideLayoutValues(
	slide,
	blockCssVars,
	breakpoint = 'desktop'
) {
	return effective(
		ensureSlideLayoutCssVars( slide, blockCssVars ),
		breakpoint
	);
}

/**
 * Merge patch into slide cssVars (hydrating first if needed).
 *
 * @param {object} slide
 * @param {object} blockCssVars
 * @param {object} nextVars Normalized responsive map
 * @return {object} Updated slide
 */
export function withSlideCssVars( slide, blockCssVars, nextVars ) {
	return {
		...( slide || {} ),
		cssVars: normalize( nextVars ),
	};
}

/**
 * Strip Layout keys from a block cssVars map (optional cleanup).
 *
 * @param {object} vars
 * @return {object}
 */
export function stripSlideLayoutVars( vars ) {
	const n = normalize( vars );
	const out = {
		desktop: { ...n.desktop },
		tablet: { ...n.tablet },
		mobile: { ...n.mobile },
	};
	[ 'desktop', 'tablet', 'mobile' ].forEach( ( bp ) => {
		SLIDE_LAYOUT_VAR_KEYS.forEach( ( key ) => {
			delete out[ bp ][ key ];
		} );
	} );
	return out;
}

/**
 * Migrate slides: copy block Layout into each slide missing cssVars.
 *
 * @param {Array} slides
 * @param {object} blockCssVars
 * @return {Array}
 */
export function migrateSlidesLayoutCssVars( slides, blockCssVars ) {
	if ( ! Array.isArray( slides ) ) {
		return slides;
	}
	const fallback = pickSlideLayoutVars( blockCssVars );
	return slides.map( ( slide ) => {
		if ( hasAny( normalize( slide?.cssVars || {} ) ) ) {
			return slide;
		}
		const seeded = hasAny( fallback )
			? merge( defaultSlideLayoutCssVars( slide?.layout ), fallback )
			: defaultSlideLayoutCssVars( slide?.layout );
		return { ...slide, cssVars: seeded };
	} );
}
