import {useState, useEffect, useMemo} from '@wordpress/element';
import {Spinner} from '@wordpress/components';
import {__} from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import Checkbox from '../components/Checkbox';
import Select from '../components/Select';
import Button from '../components/Button';
import TextInput from '../components/TextInput';
import CloseIcon from '../icons/CloseIcon';
import './GroupAdsAssignmentField.scss';
import PlusIcon from '../icons/PlusIcon';
import AdFallbackIcon from '../icons/AdFallbackIcon';

const GroupAdsAssignmentField = ( {field, value, onChange, allMetaData} ) => {
	const [assignedAds, setAssignedAds] = useState( () => {
		if ( Array.isArray( value ) && value.length > 0 && value[0].title ) {
			return value;
		}
		return [];
	} );

	const [isAssigning, setIsAssigning] = useState( false );
	const [availableAds, setAvailableAds] = useState( [] );
	const [isLoadingAds, setIsLoadingAds] = useState( false );
	const [searchQuery, setSearchQuery] = useState( '' );
	const [selection, setSelection] = useState( {} );
	const [sortConfig, setSortConfig] = useState( {key: 'weight', direction: 'desc'} );
	const isRandomMode = allMetaData.random === true || allMetaData.random === 1 || allMetaData.random === '1';
	const weightLabel = isRandomMode
		? __( 'Weight', 'adpresso' )
		: __( 'Priority', 'adpresso' );

	// Check if we already have hydrated data from the server.
	useEffect( () => {
		if ( Array.isArray( value ) && value.length > 0 ) {
			const isHydratedData = typeof value[0].title === 'object' || typeof value[0].image === 'string';

			if ( isHydratedData ) {
				setAssignedAds( value );
			}
		}
	}, [value] );

	// Load all available Ads for the assign mode
	useEffect( () => {
		if ( isAssigning && availableAds.length === 0 ) {
			setIsLoadingAds( true );
			apiFetch( {path: '/adpresso/v1/ads?per_page=-1&status=publish,draft'} )
				.then( ads => {
					setAvailableAds( ads );
					setIsLoadingAds( false );
				} )
				.catch( err => {
					console.error( err );
					setIsLoadingAds( false );
				} );
		}
	}, [isAssigning] );

	// Prepare weight options as objects for the select component
	// Format: { value: 20, label: "20" }
	const weightOptions = useMemo( () => {
		return Array.from( {length: 20}, ( _, i ) => {
			const val = 20 - i;
			return {value: val, label: String( val )};
		} );
	}, [] );

	const updateParent = ( newAdsList ) => {
		const minified = newAdsList.map( ad => ({
			ad_id:  ad.id,
			weight: ad.weight
		}) );

		onChange( field.id, minified );
	};

	const handleRemove = ( adId ) => {
		const newList = assignedAds.filter( ad => ad.id !== adId );
		setAssignedAds( newList );
		updateParent( newList );
	};

	const handleWeightChangeAssigned = ( adId, newWeight ) => {
		const newList = assignedAds.map( ad =>
			ad.id === adId ? {...ad, weight: parseInt( newWeight )} : ad
		);
		// Optional: Neu sortieren nach Gewicht
		newList.sort( ( a, b ) => b.weight - a.weight );
		setAssignedAds( newList );
		updateParent( newList );
	};

	// Handle the assign ads button
	const handleAssignAds = () => {
		const newAssignments = Object.keys( selection ).map( adId => {
			const id = parseInt( adId );
			const originalAd = availableAds.find( a => a.id === id );
			return {
				...originalAd,
				weight: parseInt( selection[adId] )
			};
		} );

		const merged = [...assignedAds, ...newAssignments];
		merged.sort( ( a, b ) => b.weight - a.weight );

		setAssignedAds( merged );
		updateParent( merged );

		// Reset and change mode
		setSelection( {} );
		setSearchQuery( '' );
		setIsAssigning( false );
	};

	const toggleSelection = ( adId, weight = 10 ) => {
		setSelection( prev => {
			const next = {...prev};
			if ( next[adId] ) {
				delete next[adId];
			} else {
				next[adId] = weight;
			}
			return next;
		} );
	};

	// Updates the weight of an already selected ad
	const updateSelectionWeight = ( adId, newWeight ) => {
		setSelection( prev => ({
			...prev,
			[adId]: newWeight
		}) );
	};

	// filter ads for selection (search + already selected are excluded)
	const filteredAvailableAds = useMemo( () => {
		return availableAds.filter( ad => {
			// don't show if already assigned.
			if ( assignedAds.some( assigned => assigned.id === ad.id ) ) {
				return false;
			}
			const titleRaw = ad.title?.raw || ad.title || '';
			const q = searchQuery.toLowerCase();

			if ( searchQuery && !String( titleRaw ).toLowerCase().includes( q ) ) {
				return false;
			}

			return true;
		} );
	}, [availableAds, assignedAds, searchQuery] );

	const renderTypeIcon = ( ad ) => {
		if ( !ad.image ) {
			return (
				<span className="adpresso-tooltip-wrapper">
					<AdFallbackIcon width="60" height="60" className="adpresso-icon-main adpresso-type-image adpresso-tooltip"/>
					<span className="adpresso-tooltip-text">
						{__( 'Type not found', 'adpresso' )}
					</span>
				</span>
			);
		}

		return (
			<span className="adpresso-tooltip-wrapper">
              <span
				  className="adpresso-type-image adpresso-tooltip"
	              dangerouslySetInnerHTML={{__html: ad.image}}
			  />
				<span className="adpresso-tooltip-text">
                  {ad.type_label || ad.type}
              </span>
           </span>
		);
	};

	const requestSort = ( key ) => {
		let direction = 'asc';
		if ( sortConfig.key === key && sortConfig.direction === 'asc' ) {
			direction = 'desc';
		}
		setSortConfig( {key, direction} );
	};

	const getSortedItems = ( items ) => {
		if ( !items ) {
			return [];
		}
		const sorted = [...items];

		sorted.sort( ( a, b ) => {
			let valA, valB;

			switch ( sortConfig.key ) {
				case 'type':
					valA = (a.type_label || a.type || '').toLowerCase();
					valB = (b.type_label || b.type || '').toLowerCase();
					break;
				case 'name':
					valA = (a.title?.raw || a.title || '').toLowerCase();
					valB = (b.title?.raw || b.title || '').toLowerCase();
					break;
				case 'status':
					valA = (a.status || '').toLowerCase();
					valB = (b.status || '').toLowerCase();
					break;
				case 'conditions':
					// Simple logic: number of conditions or string compare
					valA = (a.conditions || []).length;
					valB = (b.conditions || []).length;
					break;
				case 'weight':
				default:
					valA = a.weight || 0;
					valB = b.weight || 0;
					break;
			}

			if ( valA < valB ) {
				return sortConfig.direction === 'asc' ? - 1 : 1;
			}
			if ( valA > valB ) {
				return sortConfig.direction === 'asc' ? 1 : - 1;
			}
			return 0;
		} );
		return sorted;
	};

	const sortedAssignedAds = useMemo( () => getSortedItems( assignedAds ), [assignedAds, sortConfig] );
	const sortedFilteredAds = useMemo( () => getSortedItems( filteredAvailableAds ), [filteredAvailableAds, sortConfig] );

	// --- BULK SELECTION ---
	const isAllSelected = filteredAvailableAds.length > 0 && filteredAvailableAds.every( ad => selection[ad.id] );
	const isIndeterminate = filteredAvailableAds.some( ad => selection[ad.id] ) && !isAllSelected;

	const handleSelectAll = () => {
		if ( isAllSelected ) {
			setSelection( {} );
		} else {
			// Select everything (default value 10)
			const newSelection = {};
			filteredAvailableAds.forEach( ad => {
				newSelection[ad.id] = 10;
			} );

			// merge to keep individual weights
			setSelection( prev => ({...newSelection, ...prev}) );
		}
	};

	const SortableHeader = ( {label, sortKey, className} ) => {
		const isSorted = sortConfig.key === sortKey;
		const sortOrder = isSorted ? sortConfig.direction : '';

		return (
			<th className={`${className} adpresso-th`}>
				<div className="adpresso-th__inner">
					{label}
					<button
						type="button"
						className={`adpresso-th__sort ${isSorted ? `is-sorted ${sortOrder}` : ''}`}
						aria-label={isSorted ? (sortOrder === 'asc' ? 'Sort ascending' : 'Sort descending') : 'Sort'}
						onClick={( e ) => {
							e.preventDefault();
							requestSort( sortKey );
						}}
					>
                        <span className="adpresso-th__chevrons">
                            <span className="chev up"></span>
                            <span className="chev down"></span>
                        </span>
					</button>
				</div>
			</th>
		);
	};

	const formatConditionLabel = ( type ) => {
		if ( !type ) {
			return '';
		}
		return type
			.replace( /_/g, ' ' )
			.replace( /\b\w/g, l => l.toUpperCase() );
	};

	const formatConditionValue = ( value ) => {
		if ( Array.isArray( value ) ) {
			return value.join( ', ' );
		}
		return String( value || '' );
	};

	const getAllConditions = ( jsonString ) => {
		if ( !jsonString ) {
			return [];
		}

		try {
			const tree = typeof jsonString === 'string' ? JSON.parse( jsonString ) : jsonString;
			if ( !tree || !tree.groups || !Array.isArray( tree.groups ) ) {
				return [];
			}

			const conditions = [];
			tree.groups.forEach( group => {
				if ( group.conditions && Array.isArray( group.conditions ) ) {
					group.conditions.forEach( cond => {
						if ( cond.type ) {
							conditions.push( cond );
						}
					} );
				}
			} );
			return conditions;
		} catch ( error ) {
			return [];
		}
	};

	const renderConditions = ( conditionsTree ) => {
		const conditions = getAllConditions( conditionsTree );

		if ( conditions.length === 0 ) {
			return null;
		}

		return (
			<div className="adpresso-cell-conditions">
				{conditions.map( ( cond, index ) => {
					const label = formatConditionLabel( cond.type );
					const operator = cond.operator || 'is'; // Fallback
					const value = formatConditionValue( cond.value );
					const tooltipText = `${operator}: ${value}`;

					return (
						<span key={index} className="adpresso-badge adpresso-tooltip">
                      {label}
							<span className="adpresso-tooltip-text">
                         {tooltipText}
                      </span>
                   </span>
					);
				} )}
			</div>
		);
	};

	return (
		<div className="adpresso-group-ads-field">

			{/* VIEW MODE: List of assigned ads */}
			{!isAssigning && (
				<>
					<div className="adpresso-table-wrapper">
						<table className="adpresso-data-table">
							<thead>
							<tr>
								<SortableHeader label={__( 'Type', 'adpresso' )} sortKey="type" className="column-type"/>
								<SortableHeader label={__( 'Name', 'adpresso' )} sortKey="name" className="column-name"/>
								<SortableHeader label={__( 'Status', 'adpresso' )} sortKey="status" className="column-status"/>
								<SortableHeader label={__( 'Conditions', 'adpresso' )} sortKey="conditions" className="column-cond"/>
								<SortableHeader label={weightLabel} sortKey="weight" className="column-weight"/>
								<th className="column-action"></th>
							</tr>
							</thead>
							<tbody>
							{assignedAds.length === 0 && (
								<tr>
									<td colSpan="6" className="empty-state">{__( 'No ads assigned to this group yet.', 'adpresso' )}</td>
								</tr>
							)}
							{sortedAssignedAds.map( ad => {
								const conditionsSource = ad.conditions_tree || ad.conditions || (ad.meta_data && ad.meta_data.conditions_tree);
								const currentWeightObj = weightOptions.find( o => o.value === ad.weight ) || weightOptions[0];
								return (
									<tr key={ad.id}>
										<td className="column-type">{renderTypeIcon( ad )}</td>
										<td className="column-name"><strong>{ad.title?.raw || ad.title}</strong></td>
										<td className="column-status"><span className={`status-badge ${ad.status}`}>{ad.status}</span></td>
										<td className="column-cond">{renderConditions( conditionsSource )}</td>
										<td className="column-weight">
											<div style={{width: '90px'}}>
												<Select
													options={weightOptions}
													selected={currentWeightObj}
													setSelected={( obj ) => handleWeightChangeAssigned( ad.id, obj.value )}
													placeholder="-"
												/>
											</div>
										</td>
										<td className="column-action">
											<Button
												variant="destructive"
												icon={<CloseIcon width="9" height="9"/>}
												label={__( 'Remove', 'adpresso' )}
												className="adpresso-btn-remove adpresso-btn"
												onClick={() => handleRemove( ad.id )}
											/>
										</td>
									</tr>
								);
							} )}
							</tbody>
						</table>
					</div>

					<div className="adpresso-field-footer">
						<Button variant="primary" icon={<PlusIcon width="13" height="13"/>} className="adpresso-btn adpresso-btn-action" onClick={() => setIsAssigning( true )}>
							{__( 'Assign ads to this group', 'adpresso' )}
						</Button>
					</div>
				</>
			)}


			{/* ASSIGN MODE: Select */}
			{isAssigning && (
				<div className="adpresso-assign-panel">
					<div className="adpresso-table-wrapper selection-table scrollable adpresso-filter-popover">
						<div className="adpresso-filter-popover-header">
							<TextInput
								placeholder={__( 'Search for ads...', 'adpresso' )}
								value={searchQuery}
								onChange={setSearchQuery}
								className="adpresso-search-input adpresso-filter-popover-search adpresso-color-active"
								icon="dashicons-filter"
							/>
							<div className="adpresso-filter-popover-actions">
								<Button
									variant="primary"
									className="adpresso-btn adpresso-btn-action"
									onClick={handleAssignAds}
									disabled={Object.keys( selection ).length === 0}
								>
									{__( 'Assign', 'adpresso' )}
								</Button>
								<Button variant="inactive" className="adpresso-btn adpresso-btn-action" onClick={() => setIsAssigning( false )}>
									{__( 'Cancel', 'adpresso' )}
								</Button>
							</div>
						</div>
						{isLoadingAds ? (
							<div className="loading-state"><Spinner/></div>
						) : (
							<table className="adpresso-data-table selection-table">
								<thead>
								<tr>
									<th className="check-column">
										<Checkbox
											checked={isAllSelected}
											indeterminate={isIndeterminate}
											onChange={handleSelectAll}
										/>
									</th>
									<SortableHeader label={__( 'Type', 'adpresso' )} sortKey="type" className="column-type"/>
									<SortableHeader label={__( 'Name', 'adpresso' )} sortKey="name" className="column-name"/>
									<th className="column-weight adpresso-th">{weightLabel}</th>
								</tr>
								</thead>
								<tbody>
								{sortedFilteredAds.length === 0 && (
									<tr>
										<td colSpan="4" className="empty-state">{__( 'No ads found.', 'adpresso' )}</td>
									</tr>
								)}
								{sortedFilteredAds.map( ad => {
									const isSelected = !!selection[ad.id];
									const currentVal = selection[ad.id] || 10;
									const currentWeightObj = weightOptions.find( o => o.value === currentVal );

									return (
										<tr key={ad.id} className={isSelected ? 'is-selected' : ''}>
											<td className="check-column">
												<Checkbox
													checked={isSelected}
													onChange={() => toggleSelection( ad.id )}
												/>
											</td>
											<td className="column-type">{renderTypeIcon( ad )}</td>
											<td className="column-name">{ad.title?.raw || ad.title}</td>
											<td className="column-weight">
												{isSelected && (
													<div style={{width: '70px'}}>
														<Select
															options={weightOptions}
															selected={currentWeightObj}
															setSelected={( obj ) => updateSelectionWeight( ad.id, obj.value )}
														/>
													</div>
												)}
											</td>
										</tr>
									);
								} )}
								</tbody>
							</table>
						)}
					</div>
				</div>
			)}

		</div>
	);
};

export default GroupAdsAssignmentField;
