/**
 * Visual Schema Editor component.
 *
 * @package Schema_AI
 */

import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

const SKIP_KEYS = new Set( [ '@context', '@type', '@id' ] );
const TEXTAREA_KEYS = new Set( [ 'description', 'articleBody', 'text', 'abstract', 'reviewBody' ] );

/**
 * Determine how many columns a field should span (out of 4).
 * xs=1, sm=2, md=3, full=4
 */
function getSpan( key, value ) {
	if ( TEXTAREA_KEYS.has( key ) ) return 'full';
	if ( Array.isArray( value ) || ( value !== null && typeof value === 'object' ) ) return 'full';
	if ( typeof value === 'number' || typeof value === 'boolean' ) return 'xs';
	if ( typeof value === 'string' ) {
		if ( value.length <= 15 ) return 'xs';   // numbers-as-string, IDs, short codes
		if ( value.length <= 50 ) return 'sm';   // dates, names, short labels
		if ( value.length <= 120 ) return 'md';  // medium URLs, subtitles
		return 'full';
	}
	return 'sm';
}

function formatLabel( key ) {
	return key
		.replace( /([A-Z])/g, ' $1' )
		.replace( /^./, ( s ) => s.toUpperCase() )
		.trim();
}

function deepSet( obj, pathArr, value ) {
	const clone = JSON.parse( JSON.stringify( obj ) );
	let cur = clone;
	for ( let i = 0; i < pathArr.length - 1; i++ ) {
		if ( ! cur[ pathArr[ i ] ] ) cur[ pathArr[ i ] ] = {};
		cur = cur[ pathArr[ i ] ];
	}
	cur[ pathArr[ pathArr.length - 1 ] ] = value;
	return clone;
}

function Field( { label, value, path, onChange, span, isArray } ) {
	const key = path[ path.length - 1 ] || '';
	const isTextarea = TEXTAREA_KEYS.has( key ) || ( typeof value === 'string' && value.length > 100 );
	const cls = `saib-ve-field saib-ve-field--${ span || 'full' }`;

	if ( isArray ) {
		return (
			<div className={ cls }>
				<label className="saib-ve-label">{ label }</label>
				<textarea
					className="saib-ve-textarea saib-ve-textarea--code"
					value={ JSON.stringify( value, null, 2 ) }
					rows={ 3 }
					onChange={ ( e ) => {
						try { onChange( path, JSON.parse( e.target.value ) ); } catch ( err ) {}
					} }
					spellCheck={ false }
				/>
			</div>
		);
	}

	if ( isTextarea ) {
		return (
			<div className={ cls }>
				<label className="saib-ve-label">{ label }</label>
				<textarea
					className="saib-ve-textarea"
					value={ value || '' }
					rows={ 4 }
					onChange={ ( e ) => onChange( path, e.target.value ) }
				/>
			</div>
		);
	}

	return (
		<div className={ cls }>
			<label className="saib-ve-label">{ label }</label>
			<input
				className="saib-ve-input"
				type="text"
				value={ value != null ? String( value ) : '' }
				onChange={ ( e ) => onChange( path, e.target.value ) }
			/>
		</div>
	);
}

function ObjectGroup( { label, obj, path, onChange, depth = 0 } ) {
	const [ open, setOpen ] = useState( depth === 0 );

	if ( depth > 2 ) return null;

	return (
		<div className="saib-ve-group">
			<button
				type="button"
				className={ `saib-ve-group-toggle${ open ? ' saib-ve-group-toggle--open' : '' }` }
				onClick={ () => setOpen( ! open ) }
			>
				<span className="saib-ve-group-arrow">{ open ? '▾' : '▸' }</span>
				{ label }
			</button>
			{ open && (
				<div className="saib-ve-grid saib-ve-group-body">
					{ Object.entries( obj ).map( ( [ k, v ] ) =>
						renderValue( k, v, [ ...path, k ], onChange, depth + 1 )
					) }
				</div>
			) }
		</div>
	);
}

function renderValue( key, value, path, onChange, depth = 0 ) {
	if ( SKIP_KEYS.has( key ) ) return null;
	const label = formatLabel( key );

	if ( Array.isArray( value ) ) {
		return (
			<Field
				key={ path.join( '.' ) }
				label={ label }
				value={ value }
				path={ path }
				onChange={ onChange }
				isArray
			/>
		);
	}

	if ( value !== null && typeof value === 'object' ) {
		return (
			<ObjectGroup
				key={ path.join( '.' ) }
				label={ label }
				obj={ value }
				path={ path }
				onChange={ onChange }
				depth={ depth }
			/>
		);
	}

	const span = getSpan( key, value );
	return (
		<Field
			key={ path.join( '.' ) }
			label={ label }
			value={ value }
			path={ path }
			onChange={ onChange }
			span={ span }
		/>
	);
}

function VisualEditor( { schema, onChange, schemaType } ) {
	if ( ! schema || typeof schema !== 'object' ) return null;

	const handleChange = ( pathArr, value ) => {
		onChange( deepSet( schema, pathArr, value ) );
	};

	return (
		<div className="saib-visual-editor">
			<div className="saib-ve-type-row">
				<span className="saib-ve-type-label">{ __( 'Type', 'schema-ai' ) }</span>
				<span className="saib-schema-type">{ schema[ '@type' ] || schemaType }</span>
			</div>

			<div className="saib-ve-grid">
				{ Object.entries( schema ).map( ( [ key, value ] ) =>
					renderValue( key, value, [ key ], handleChange, 0 )
				) }
			</div>
		</div>
	);
}

export default VisualEditor;
