import { __ } from '@wordpress/i18n';
import {
	useBlockProps,
	useInnerBlocksProps,
	InspectorControls,
	store as blockEditorStore,
} from '@wordpress/block-editor';
import { useEffect, useRef, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import {
	PanelBody,
	Button,
	SelectControl,
	TabPanel,
	TextControl,
} from '@wordpress/components';
import { cog, plus, styles } from '@wordpress/icons';
import './editor.scss';
import { useUniqueBlockClass } from '../../components/hooks/useUniqueBlockClass';
import {
	useDeviceSettings,
	generateBlockStyles,
} from '../../components/controls/blockStyles';
import { generateBlockStylesHover } from '../../components/controls/blockStylesHover';
import LabeledAppender from '../../components/controls/LabeledAppender';
import { BODYCOPY_BLOCK } from '../table/utils';
import { useAddCell, useAddRow } from '../table/structureActions';
import { StylePanel } from './components/StylePanel';
import TableCellToolbar from './components/TableCellToolbar';

const CELL_TAGS = [
	{ label: __( 'Data Cell (td)', 'axcelersblocks' ), value: 'td' },
	{ label: __( 'Header Cell (th)', 'axcelersblocks' ), value: 'th' },
];

const SCOPE_OPTIONS = [
	{ label: __( 'None', 'axcelersblocks' ), value: '' },
	{ label: __( 'Row', 'axcelersblocks' ), value: 'row' },
	{ label: __( 'Column', 'axcelersblocks' ), value: 'col' },
	{ label: __( 'Row group', 'axcelersblocks' ), value: 'rowgroup' },
	{ label: __( 'Column group', 'axcelersblocks' ), value: 'colgroup' },
];

function CellSettings( { attributes, setAttributes } ) {
	const { tagName = 'td', scope = '', colSpan = 1, rowSpan = 1 } = attributes;

	return (
		<PanelBody title={ __( 'Cell', 'axcelersblocks' ) } initialOpen>
			<SelectControl
				label={ __( 'Cell Tag', 'axcelersblocks' ) }
				help={ __(
					'Use a header cell (th) for row or column headers, otherwise a data cell (td).',
					'axcelersblocks'
				) }
				value={ tagName }
				options={ CELL_TAGS }
				onChange={ ( value ) => setAttributes( { tagName: value } ) }
			/>
			{ tagName === 'th' && (
				<SelectControl
					label={ __( 'Scope', 'axcelersblocks' ) }
					help={ __(
						'Tells assistive tech which cells this header applies to.',
						'axcelersblocks'
					) }
					value={ scope }
					options={ SCOPE_OPTIONS }
					onChange={ ( value ) => setAttributes( { scope: value } ) }
				/>
			) }
			<TextControl
				type="number"
				min={ 1 }
				label={ __( 'Column Span', 'axcelersblocks' ) }
				value={ colSpan }
				onChange={ ( value ) =>
					setAttributes( {
						colSpan: Math.max( 1, parseInt( value, 10 ) || 1 ),
					} )
				}
			/>
			<TextControl
				type="number"
				min={ 1 }
				label={ __( 'Row Span', 'axcelersblocks' ) }
				value={ rowSpan }
				onChange={ ( value ) =>
					setAttributes( {
						rowSpan: Math.max( 1, parseInt( value, 10 ) || 1 ),
					} )
				}
			/>
		</PanelBody>
	);
}

export default function Edit( {
	attributes,
	setAttributes,
	clientId,
	isSelected,
} ) {
	const {
		anchor,
		uniqueClass,
		tagName = 'td',
		colSpan = 1,
		rowSpan = 1,
	} = attributes;

	useUniqueBlockClass( {
		clientId,
		uniqueClass,
		setAttributes,
		blockName: 'axcelersblocks-table-cell',
	} );

	const devices = useDeviceSettings();
	const [ activeStyleTab, setActiveStyleTab ] = useState( 'main' );
	const [ rowInserterStyle, setRowInserterStyle ] = useState( undefined );
	const cellRef = useRef( null );
	const {
		rowId,
		sectionId,
		isLastCellInRow,
		isLastRowInSection,
		isTableActive,
	} = useSelect(
		( select ) => {
			const store = select( blockEditorStore );
			const currentRowId = store.getBlockRootClientId( clientId );
			const currentSectionId = currentRowId
				? store.getBlockRootClientId( currentRowId )
				: null;
			const tableId = currentSectionId
				? store.getBlockRootClientId( currentSectionId )
				: null;
			const cellOrder = currentRowId
				? store.getBlockOrder( currentRowId )
				: [];
			const rowOrder = currentSectionId
				? store.getBlockOrder( currentSectionId )
				: [];

			return {
				rowId: currentRowId,
				sectionId: currentSectionId,
				isLastCellInRow:
					cellOrder.length > 0 &&
					cellOrder[ cellOrder.length - 1 ] === clientId,
				isLastRowInSection:
					rowOrder.length > 0 &&
					rowOrder[ rowOrder.length - 1 ] === currentRowId,
				isTableActive:
					!! tableId &&
					( store.isBlockSelected( tableId ) ||
						store.hasSelectedInnerBlock( tableId, true ) ),
			};
		},
		[ clientId ]
	);
	const addCell = useAddCell( rowId );
	const addRow = useAddRow( sectionId );

	// Contextual "add block" affordance: only while this cell (or a block inside
	// it) is active, so the table canvas stays clean.
	const hasSelectedInnerBlock = useSelect(
		( select ) =>
			select( blockEditorStore ).hasSelectedInnerBlock( clientId, true ),
		[ clientId ]
	);
	const showAppender = isSelected || hasSelectedInnerBlock;

	useEffect( () => {
		if ( ! isTableActive || ! isLastCellInRow || ! isLastRowInSection ) {
			setRowInserterStyle( undefined );
			return undefined;
		}

		const updateRowInserterStyle = () => {
			const cell = cellRef.current;
			const table = cell?.closest( 'table' );

			if ( ! cell || ! table ) {
				return;
			}

			const cellRect = cell.getBoundingClientRect();
			const tableRect = table.getBoundingClientRect();

			setRowInserterStyle( {
				left: `${ tableRect.left - cellRect.left }px`,
				width: `${ tableRect.width }px`,
			} );
		};

		updateRowInserterStyle();
		const frame = window.requestAnimationFrame( updateRowInserterStyle );
		window.addEventListener( 'resize', updateRowInserterStyle );

		return () => {
			window.cancelAnimationFrame( frame );
			window.removeEventListener( 'resize', updateRowInserterStyle );
		};
	}, [ isLastCellInRow, isLastRowInSection, isTableActive, rowId, sectionId ] );

	const blockProps = useBlockProps( {
		id: anchor || undefined,
		ref: cellRef,
		className: [ 'axcelersblocks-table-cell', uniqueClass ]
			.filter( Boolean )
			.join( ' ' ),
		colSpan: colSpan > 1 ? colSpan : undefined,
		rowSpan: rowSpan > 1 ? rowSpan : undefined,
	} );

	const { children: cellChildren, ...innerBlocksProps } = useInnerBlocksProps(
		blockProps,
		{
			allowedBlocks: [ BODYCOPY_BLOCK ],
			// A cell is never empty: seed a bodycopy carrying placeholder text.
			template: [ [ BODYCOPY_BLOCK, { tagName: 'p', content: 'Data' } ] ],
			templateLock: false,
			orientation: 'vertical',
			renderAppender: showAppender
				? () => (
						<LabeledAppender
							rootClientId={ clientId }
							label={ __( 'Add block', 'axcelersblocks' ) }
							iconOnly
							className="axcelersblocks-table-cell__add"
						/>
				  )
				: false,
		}
	);

	const TagName = tagName;

	return (
		<>
			<TableCellToolbar clientId={ clientId } />

			<InspectorControls>
				<TabPanel
					className="axcelersblocks-tabs"
					activeClass="is-active"
					tabs={ [
						{
							name: 'settings',
							title: <>{ cog }</>,
							className: 'settings-tab',
						},
						{
							name: 'style',
							title: <>{ styles }</>,
							className: 'style-tab',
						},
					] }
				>
					{ ( tab ) => (
						<>
							{ tab.name === 'settings' && (
								<CellSettings
									attributes={ attributes }
									setAttributes={ setAttributes }
								/>
							) }
							{ tab.name === 'style' && (
								<StylePanel
									attributes={ attributes }
									setAttributes={ setAttributes }
									uniqueClass={ uniqueClass }
									tagName={ tagName }
									activeTab={ activeStyleTab }
									setActiveTab={ setActiveStyleTab }
								/>
							) }
						</>
					) }
				</TabPanel>
			</InspectorControls>

			{ uniqueClass ? (
				<style>
					{ generateBlockStyles( uniqueClass, devices, attributes ) }
					{ generateBlockStylesHover(
						uniqueClass,
						devices,
						attributes
					) }
				</style>
			) : null }

			<TagName { ...innerBlocksProps }>
				{ cellChildren }
				{ isTableActive && isLastCellInRow && (
					<div
						className="axb-table-cell-inserter axb-table-cell-inserter--cell"
						contentEditable={ false }
					>
						<Button
							className="axb-table-cell-inserter__btn"
							icon={ plus }
							label={ __( 'Add Cell', 'axcelersblocks' ) }
							onClick={ addCell }
							showTooltip
						/>
					</div>
				) }
				{ isTableActive && isLastCellInRow && isLastRowInSection && (
					<div
						className="axb-table-cell-inserter axb-table-cell-inserter--row"
						contentEditable={ false }
						style={ rowInserterStyle }
					>
						<Button
							className="axb-table-cell-inserter__btn"
							icon={ plus }
							onClick={ addRow }
						>
							{ __( 'Add Row', 'axcelersblocks' ) }
						</Button>
					</div>
				) }
			</TagName>
		</>
	);
}
