import { useReducer, useEffect, useState } from '@wordpress/element';
import { Button, TextControl, TextareaControl, CheckboxControl, Spinner } from '@wordpress/components';
import { DndContext, DragOverlay, pointerWithin } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import apiFetch from '@wordpress/api-fetch';
import BlockPalette from '../components/BlockPalette';
import BuilderCanvas from '../components/BuilderCanvas';
import SchemaPreview from '../components/SchemaPreview';

let blockIdCounter = 0;

function generateBlockId() {
	blockIdCounter += 1;
	return `block-${ blockIdCounter }`;
}

const initialState = {
	tool_name: '',
	description: '',
	required_roles: [ 'administrator' ],
	blocks: [],
};

function reducer( state, action ) {
	switch ( action.type ) {
		case 'SET_TOOL_NAME':
			return { ...state, tool_name: action.payload };

		case 'SET_DESCRIPTION':
			return { ...state, description: action.payload };

		case 'SET_REQUIRED_ROLES':
			return { ...state, required_roles: action.payload };

		case 'ADD_BLOCK': {
			const config = {
				fields: [],
				meta_keys: {},
				taxonomies: {},
				filters: {},
			};
			if ( 'posts' === action.payload ) {
				config.post_type = 'post';
			}
			return {
				...state,
				blocks: [
					...state.blocks,
					{
						id: generateBlockId(),
						block_type: action.payload,
						config,
					},
				],
			};
		}

		case 'REMOVE_BLOCK':
			return {
				...state,
				blocks: state.blocks.filter( ( b ) => b.id !== action.payload ),
			};

		case 'UPDATE_BLOCK_CONFIG':
			return {
				...state,
				blocks: state.blocks.map( ( b ) =>
					b.id === action.payload.id
						? { ...b, config: { ...b.config, ...action.payload.config } }
						: b
				),
			};

		case 'REORDER_BLOCKS': {
			const { oldIndex, newIndex } = action.payload;
			const blocks = [ ...state.blocks ];
			const [ moved ] = blocks.splice( oldIndex, 1 );
			blocks.splice( newIndex, 0, moved );
			return { ...state, blocks };
		}

		case 'LOAD_TOOL':
			return action.payload;

		default:
			return state;
	}
}

export default function ToolBuilder( { toolId, navigate } ) {
	const [ state, dispatch ] = useReducer( reducer, initialState );
	const [ saving, setSaving ] = useState( false );
	const [ saveError, setSaveError ] = useState( '' );
	const [ loaded, setLoaded ] = useState( ! toolId );
	const [ activeDragType, setActiveDragType ] = useState( null );

	useEffect( () => {
		if ( toolId ) {
			apiFetch( { path: `wlconduit/v1/tools/${ toolId }` } )
				.then( ( response ) => {
					const config = response.config || {};
					// Add unique IDs to blocks for drag-and-drop.
					const blocks = ( config.blocks || [] ).map( ( b ) => ( {
						id: generateBlockId(),
						block_type: b.block_type,
						config: b.config || {},
					} ) );

					dispatch( {
						type: 'LOAD_TOOL',
						payload: {
							tool_name: config.tool_name || '',
							description: config.description || '',
							required_roles: config.required_roles || [ 'administrator' ],
							blocks,
						},
					} );
					setLoaded( true );
				} )
				.catch( () => {
					window.alert( 'Failed to load tool.' );
					navigate( '/' );
				} );
		}
	}, [ toolId ] );

	async function handleSave() {
		if ( ! state.tool_name.trim() ) {
			setSaveError( 'Tool name is required.' );
			return;
		}

		setSaving( true );
		setSaveError( '' );

		const payload = {
			tool_name: state.tool_name,
			description: state.description,
			required_roles: state.required_roles,
			blocks: state.blocks.map( ( b ) => ( {
				block_type: b.block_type,
				config: b.config,
			} ) ),
		};

		try {
			if ( toolId ) {
				await apiFetch( {
					path: `wlconduit/v1/tools/${ toolId }`,
					method: 'PUT',
					data: payload,
				} );
			} else {
				await apiFetch( {
					path: 'wlconduit/v1/tools',
					method: 'POST',
					data: payload,
				} );
			}
			navigate( '/' );
		} catch ( err ) {
			setSaveError( err.message || 'Failed to save tool.' );
		}

		setSaving( false );
	}

	function handleDragStart( event ) {
		const { active } = event;
		if ( active.data.current?.type === 'palette' ) {
			setActiveDragType( active.data.current.blockType );
		}
	}

	function handleDragEnd( event ) {
		const { active, over } = event;
		setActiveDragType( null );

		// Dropping from palette onto canvas.
		if ( active.data.current?.type === 'palette' && over?.id === 'canvas' ) {
			dispatch( { type: 'ADD_BLOCK', payload: active.data.current.blockType } );
			return;
		}

		// Reordering within canvas.
		if (
			active.data.current?.type === 'canvas-block' &&
			over?.data.current?.type === 'canvas-block'
		) {
			const oldIndex = state.blocks.findIndex( ( b ) => b.id === active.id );
			const newIndex = state.blocks.findIndex( ( b ) => b.id === over.id );
			if ( oldIndex !== newIndex ) {
				dispatch( { type: 'REORDER_BLOCKS', payload: { oldIndex, newIndex } } );
			}
		}
	}

	if ( ! loaded ) {
		return <Spinner />;
	}

	const blockDefinitions = window.wlconduitData?.blocks || {};

	return (
		<div className="aic-tool-builder">
			<div className="aic-builder-header">
				<Button variant="tertiary" onClick={ () => navigate( '/' ) }>
					&larr; Back to Tools
				</Button>
				<h1>{ toolId ? 'Edit Tool' : 'Create New Tool' }</h1>
				<Button
					variant="primary"
					onClick={ handleSave }
					isBusy={ saving }
					disabled={ saving }
				>
					{ toolId ? 'Update' : 'Publish' }
				</Button>
			</div>

			<div className="aic-builder-settings">
				<TextControl
					label="Tool Name"
					help="A unique identifier for this tool (e.g., search_posts). Use lowercase with underscores."
					value={ state.tool_name }
					onChange={ ( val ) => { dispatch( { type: 'SET_TOOL_NAME', payload: val } ); setSaveError( '' ); } }
				/>
				{ saveError && (
					<p className="aic-save-error" style={ { color: '#cc1818', fontSize: '13px', margin: '-8px 0 12px' } }>
						{ saveError }
					</p>
				) }
				<TextareaControl
					label="Description"
					help="Describe what this tool does. The AI uses this to decide when to call it."
					value={ state.description }
					onChange={ ( val ) => dispatch( { type: 'SET_DESCRIPTION', payload: val } ) }
				/>
				<fieldset className="aic-required-roles">
					<legend>Required Roles</legend>
					<p className="aic-selector-hint">Select which roles can access this tool. Administrator is always included.</p>
					{ ( window.wlconduitData?.roles || [] ).map( ( r ) => (
						<CheckboxControl
							key={ r.name }
							label={ r.label }
							checked={ ( state.required_roles || [] ).includes( r.name ) }
							disabled={ r.name === 'administrator' }
							onChange={ ( checked ) => {
								const current = state.required_roles || [ 'administrator' ];
								const updated = checked
									? [ ...current, r.name ]
									: current.filter( ( role ) => role !== r.name );
								dispatch( { type: 'SET_REQUIRED_ROLES', payload: updated } );
							} }
						/>
					) ) }
				</fieldset>
			</div>

			<DndContext
				collisionDetection={ pointerWithin }
				onDragStart={ handleDragStart }
				onDragEnd={ handleDragEnd }
			>
				<div className="aic-builder-workspace">
					<BlockPalette definitions={ blockDefinitions } />
					<BuilderCanvas
						blocks={ state.blocks }
						definitions={ blockDefinitions }
						dispatch={ dispatch }
					/>
					<SchemaPreview state={ state } definitions={ blockDefinitions } />
				</div>

				<DragOverlay>
					{ activeDragType && (
						<div className="aic-palette-item aic-palette-item--dragging">
							<span className={ `dashicons dashicons-${ blockDefinitions[ activeDragType ]?.icon || 'block-default' }` } />
							<span>{ blockDefinitions[ activeDragType ]?.label || activeDragType }</span>
						</div>
					) }
				</DragOverlay>
			</DndContext>
		</div>
	);
}
