import {useEffect, useState, useCallback, useRef} from '@wordpress/element';
import {addQueryArgs} from '@wordpress/url';
import {Spinner} from '@wordpress/components';
import {__} from '@wordpress/i18n';
import ModalHeader from './ModalHeader';
import ModalFooter from './ModalFooter';
import SectionRenderer from './SectionRenderer';
import {clearAssignmentCacheForItem} from '../../../design/form-fields/AssignmentField';

const ModalEntityEditor = ( {context = {}, closeModal, setModalTitle, setHasUnsavedChanges, isFullscreen, setIsFullscreen} ) => {
	// Use the context as a start value for our internal navigation.
	const [editingEntity, setEditingEntity] = useState( {entityType: context.entityType, entityId: context.entityId} );
	const [navigationStack, setNavigationStack] = useState( context.navigationStack || [] );
	const navigableIds = context.navigableIds || [];

	const isNewItem = !editingEntity?.entityId || editingEntity.entityId === 0;
	const [entityCache, setEntityCache] = useState( {} );
	const [entityData, setEntityData] = useState( null );
	const [isLoading, setIsLoading] = useState( false );
	const [isSaving, setIsSaving] = useState( false );
	const [isDirty, setIsDirty] = useState( false );
	const assignmentFieldRef = useRef( null );

	// Communicate unsaved changes to the modal
	useEffect( () => {
		setHasUnsavedChanges( isDirty );
	}, [isDirty, setHasUnsavedChanges] );

	// Communicate the title to the modal
	useEffect( () => {
		if ( entityData && entityData.title && !isNewItem ) {
			setModalTitle( __( 'Edit: ', 'adpresso' ) + entityData.title );
		} else {
			setModalTitle( isNewItem ? __( 'Create Item', 'adpresso' ) : __( 'Edit Item', 'adpresso' ) );
		}
	}, [isNewItem, entityData, setModalTitle] );

	const handleSetDirty = useCallback( () => {
		setIsDirty( true );
	}, [] );

	const handleNavigateBack = () => {
		if ( isDirty && !window.confirm( __( 'You have unsaved changes...', 'adpresso' ) ) ) {
			return;
		}
		setIsDirty( false );

		const previousEntity = navigationStack[navigationStack.length - 1];
		if ( previousEntity ) {
			setEditingEntity( previousEntity );
			setNavigationStack( prevStack => prevStack.slice( 0, - 1 ) );
		}
	};

	useEffect( () => {
		if ( !editingEntity ) {
			setEntityData( null );
			return;
		}

		const {entityType, entityId} = editingEntity;

		if ( !isNewItem && entityCache[entityId] ) {
			setEntityData( entityCache[entityId] );
			setTimeout( () => setIsLoading( false ), 100 );
			return;
		}

		const abortController = new AbortController();
		const {signal} = abortController;

		const fetchData = async () => {
			setIsLoading( true );
			setEntityData( null );

			try {
				let endpoint = isNewItem ? `adpresso/v1/schema/${entityType}` : `adpresso/v1/${entityType}/${entityId}`;
				const data = await wp.apiFetch( {path: endpoint, signal} );

				if ( isNewItem ) {
					const newTitleMapping = {
						'ads':        __( 'New Ad', 'adpresso' ),
						'groups':     __( 'New Group', 'adpresso' ),
						'placements': __( 'New Placement', 'adpresso' )
					};
					data.title = newTitleMapping[entityType] || __( 'New Item', 'adpresso' );
				}

				setEntityData( data );
				if ( !isNewItem ) {
					setEntityCache( prevCache => ({...prevCache, [entityId]: data}) );
				}

			} catch ( error ) {
				if ( error.name !== 'AbortError' ) {
					console.error( `Error fetching entity data:`, error );
				}
			} finally {
				if ( !signal.aborted ) {
					setIsLoading( false );
				}
			}
		};

		fetchData();
		return () => abortController.abort();
	}, [editingEntity, entityCache, isNewItem] );

	const handleDataChange = useCallback( ( fieldId, newValue, metaKey = null ) => {
		setIsDirty( true );
		setEntityData( prevData => {
			if ( !prevData ) {
				return prevData;
			}
			const newMetaData = {...prevData.meta_data};

			if ( fieldId === 'content' ) {
				return {...prevData, content: newValue};
			}

			if ( fieldId === 'conditions_tree' ) {
				if ( newValue == null || newValue === '' ) {
					return prevData;
				}
				try { JSON.parse( newValue ); } catch { return prevData; }
			}

			if ( metaKey ) {
				newMetaData[metaKey] = {...(newMetaData[metaKey] || {}), [fieldId]: newValue};
			} else {
				newMetaData[fieldId] = newValue;
			}

			return {...prevData, meta_data: newMetaData};
		} );
	}, [] );

	const handleStatusChange = ( newStatus ) => {
		setEntityData( prevData => ({...prevData, status: newStatus}) );
		setIsDirty( true );
	};

	const handleClone = useCallback( () => {
		if ( isDirty && !window.confirm( __( 'You have unsaved changes that will be lost. Are you sure you want to clone this item?', 'adpresso' ) ) ) {
			return;
		}

		setIsLoading( true );
		const {entityType, entityId} = editingEntity;

		wp.apiFetch( {path: `adpresso/v1/duplicate/${entityType}/${entityId}`, method: 'POST'} )
		  .then( newEntityData => {
			  setEntityCache( prevCache => ({...prevCache, [newEntityData.id]: newEntityData}) );
			  setEditingEntity( {entityType: entityType, entityId: newEntityData.id} );
			  setIsDirty( false );
		  } )
		  .catch( error => {
			  console.error( 'Clone failed:', error );
			  alert( 'Could not clone the item. ' + error.message );
			  setIsLoading( false );
		  } );
	}, [editingEntity, isDirty] );

	const handleSave = async () => {
		if ( !isDirty ) {
			return;
		}
		setIsSaving( true );
		const {entityType, entityId} = editingEntity;

		try {
			const assignmentChanges = assignmentFieldRef.current?.getChanges() || [];
			const payload = {
				title:              entityData.title,
				status:             entityData.status || 'draft',
				content:            entityData.content || '',
				meta_data:          entityData.meta_data,
				assignment_changes: assignmentChanges
			};

			let response;
			if ( isNewItem ) {
				response = await wp.apiFetch( {path: `adpresso/v1/${entityType}`, method: 'POST', data: {...payload, entity_type: entityType}} );
			} else {
				response = await wp.apiFetch( {path: `adpresso/v1/${entityType}/${entityId}`, method: 'POST', data: payload} );
			}

			setEntityCache( prevCache => ({...prevCache, [response.id]: response}) );
			setEntityData( response );
			setIsDirty( false );
			clearAssignmentCacheForItem( response.id );

			if ( isNewItem ) {
				setEditingEntity( {entityType, entityId: response.id} );
				const newUrl = addQueryArgs( window.location.href, {action: 'edit', entity_type: entityType, entity_id: response.id} );
				window.history.pushState( {path: newUrl}, '', newUrl );
			}

			const eventName = isNewItem ? 'adpresso:entityCreated' : 'adpresso:entityUpdated';
			const eventMessage = isNewItem ? __( 'Items successfully created.', 'adpresso' ) : __( 'Items successfully updated.', 'adpresso' );
			AdPresso.events.dispatch( eventName, {bubbles: true, detail: {entityType: entityType, entityId: isNewItem ? response.id : entityId, updatedData: response}} );

			if ( window.AdPresso?.notifications ) {
				window.AdPresso.notifications.addSuccess( eventMessage );
			}

		} catch ( error ) {
			console.error( 'Error saving entity:', error );
			alert( 'Error: Could not save changes.' );
			if ( window.AdPresso?.notifications ) {
				window.AdPresso.notifications.addError( __( 'Item couldn´t be created.', 'adpresso' ) );
			}
		} finally {
			setIsSaving( false );
		}
	};

	const handleRefresh = () => {
		if ( isDirty && !window.confirm( __( 'You have unsaved changes that will be lost. Are you sure you want to refresh?', 'adpresso' ) ) ) {
			return;
		}
		setIsDirty( false );
		const {entityId} = editingEntity;

		setEntityCache( prevCache => {
			const newCache = {...prevCache};
			delete newCache[entityId];
			return newCache;
		} );

		setIsLoading( true );
		setEditingEntity( {...editingEntity} );
	};

	const handleDelete = async () => {
		if ( !window.confirm( __( 'Are you sure you want to move this item to the trash?', 'adpresso' ) ) ) {
			return;
		}

		setIsSaving( true );
		const {entityType, entityId} = editingEntity;

		try {
			await wp.apiFetch( {path: `adpresso/v1/${entityType}/${entityId}`, method: 'DELETE'} );
			AdPresso.events.dispatch( 'adpresso:entityDeleted', {entityType: entityType, entityId: entityId} );
			closeModal();
		} catch ( error ) {
			console.error( 'Error deleting entity:', error );
			alert( 'Error: Could not delete item.' );
		} finally {
			setIsSaving( false );
		}
	};

	const handleTitleChange = ( newTitle ) => {
		setEntityData( prevData => ({...prevData, title: newTitle}) );
		setIsDirty( true );
	};

	const handleNavigation = ( direction ) => {
		if ( isDirty && !window.confirm( __( 'You have unsaved changes. Are you sure you want to navigate away?', 'adpresso' ) ) ) {
			return;
		}

		setIsLoading( true );
		const currentId = editingEntity.entityId;
		const currentIndex = navigableIds.indexOf( currentId );
		if ( currentIndex === - 1 ) {
			return;
		}

		let newEntityId = null;
		if ( direction === 'prev' && currentIndex > 0 ) {
			newEntityId = navigableIds[currentIndex - 1];
		} else if ( direction === 'next' && currentIndex < navigableIds.length - 1 ) {
			newEntityId = navigableIds[currentIndex + 1];
		}

		if ( newEntityId ) {
			setIsDirty( false );
			setEditingEntity( prev => ({...prev, entityId: newEntityId}) );
		}
	};

	const currentIndex = navigableIds.indexOf( editingEntity?.entityId );
	const isPrevDisabled = currentIndex <= 0;
	const isNextDisabled = currentIndex >= navigableIds.length - 1;
	const previousEntity = navigationStack.length > 0 ? navigationStack[navigationStack.length - 1] : null;

	if ( isLoading ) {
		return <div className="adpresso-modal-spinner"><Spinner/></div>;
	}

	if ( !entityData ) {
		return null;
	}

	return (
		<div className="adpresso-modal-content">
			<ModalHeader
				entityData={entityData}
				onTitleChange={handleTitleChange}
				onNavigate={handleNavigation}
				onClose={closeModal}
				isPrevDisabled={isPrevDisabled}
				isNextDisabled={isNextDisabled}
				onNavigateBack={handleNavigateBack}
				previousEntity={previousEntity}
				onRefresh={handleRefresh}
				setIsFullscreen={setIsFullscreen}
				isFullscreen={isFullscreen}
			/>
			<SectionRenderer
				sections={entityData.edit_ui_sections}
				allMetaData={entityData.meta_data}
				onDataChange={handleDataChange}
				availableConditions={entityData.condition_builder_data}
				entityData={entityData}
				ref={assignmentFieldRef}
				onSetDirty={handleSetDirty}
			/>
			<ModalFooter
				entityData={entityData}
				onSave={handleSave}
				onDelete={handleDelete}
				onStatusChange={handleStatusChange}
				onClone={handleClone}
				isDirty={isDirty}
				isSaving={isSaving}
				isNewItem={isNewItem}
			/>
		</div>
	);
};

export default ModalEntityEditor;
