import * as React from 'react'
import {__, _x} from '@wordpress/i18n'
import cx from 'classnames'

import {
	hasBlockSupport,
	// @ts-expect-error
} from '@wordpress/blocks'

import {
	addFilter,
} from '@wordpress/hooks'

import {
	InspectorAdvancedControls,
	// @ts-expect-error
} from '@wordpress/block-editor'

import {
	ToggleControl,
} from '@wordpress/components'

import {
	createHigherOrderComponent,
} from '@wordpress/compose'

import {
	WithTooltip,
} from '@ska/components'

import type {
	tBlockAttributes,
	tBlockEditProps,
	tBlockListBlockProps,
	tBlockNameOrType,
	tBlockType,
} from '@ska/shared'

export interface RenderValue {
	/** Don't render the block in the editor, adds `[data-ska-editor-no-render]` attribute that has CSS applied to hide the block unless it has the `.is-selected` or `.is-child-selected` classes. */
	editorNoRender?: boolean
	/** Don't render the block on the front end. Adds `wp-no-render` class. */
	noRender?: boolean
}

export interface RenderAttributes {
	skaBlocksRender?: RenderValue
}

export const RENDER_SUPPORT_KEY = 'skaBlocksRender'
export const hasRenderSupport = (block: tBlockNameOrType) => hasBlockSupport(block, 'customClassName', true)

const NO_RENDER_PREFIX = '🛑 '
const EDITOR_NO_RENDER_PREFIX = '🚫 '

const getBlockLabelRenderer = (defaultLabel: string, __experimentalLabel?: tBlockType['__experimentalLabel']) => {

	const getLabel: tBlockType['__experimentalLabel'] = (attributes, arg) => {

		const {context} = arg
		const label = __experimentalLabel ? (__experimentalLabel(attributes, arg) || defaultLabel) : defaultLabel

		if(context !== 'list-view' || typeof label !== 'string') {
			return label
		}

		const {
			skaBlocksRender = {},
		} = attributes

		const {
			editorNoRender = false,
			noRender = false,
		} = skaBlocksRender

		return `${noRender ? NO_RENDER_PREFIX : ''}${editorNoRender ? EDITOR_NO_RENDER_PREFIX : ''}${label}`
	}

	return getLabel
}

const withRenderSupport = (settings: tBlockType) => {

	if(!hasRenderSupport(settings)) {
		return settings
	}

	if(!settings.attributes.skaBlocksRender) {

		Object.assign(settings.attributes, {
			skaBlocksRender: {
				type: 'object',
			},
		})
	}

	settings.__experimentalLabel = getBlockLabelRenderer(settings.title, settings.__experimentalLabel)

	return settings
}

const RenderInspectorControls: React.FC<tBlockEditProps<RenderAttributes>> = (props) => {

	const {
		attributes,
		setAttributes,
	} = props

	const {
		skaBlocksRender = {},
	} = attributes

	const {
		editorNoRender = false,
		noRender = false,
	} = skaBlocksRender

	return <>
		<InspectorAdvancedControls>
			<WithTooltip
				label={__('View help', 'ska-blocks')}
				tooltip={__(`Hide this block in the editor unless it is selected.`, 'ska-blocks')}
			>
				<ToggleControl
					label={`${EDITOR_NO_RENDER_PREFIX}${__('Hide in editor', 'ska-blocks')}`}
					checked={editorNoRender}
					onChange={() => setAttributes({skaBlocksRender: {...skaBlocksRender, editorNoRender: !editorNoRender}})}
					__nextHasNoMarginBottom
				/>
			</WithTooltip>
			<WithTooltip
				label={__('View help', 'ska-blocks')}
				tooltip={__(`Disable rendering this block on the front end.`, 'ska-blocks')}
			>
				<ToggleControl
					label={`${NO_RENDER_PREFIX}${__('No render', 'ska-blocks')}`}
					checked={noRender}
					onChange={() => setAttributes({skaBlocksRender: {...skaBlocksRender, noRender: !noRender}})}
					__nextHasNoMarginBottom
				/>
			</WithTooltip>
		</InspectorAdvancedControls>
	</>
}

const withRenderControls = createHigherOrderComponent(
	(BlockEdit: any) => (props: tBlockEditProps) => {
		if(hasRenderSupport(props.name)) {
			return <>
				<RenderInspectorControls {...props as any as tBlockEditProps<RenderAttributes>} />
				<BlockEdit {...props} />
			</>
		}
		return <BlockEdit {...props} />
	},
	'withSkaBlocksRender'
)

const withRenderClassNames = (props: {className?: string}, blockType: tBlockType, attributes: tBlockAttributes): object => {

	const {
		skaBlocksRender = {},
	} = attributes

	const {
		noRender = false,
	} = skaBlocksRender

	if(!noRender) {
		return props
	}

	return {
		...props,
		className: cx(props.className, 'wp-no-render'),
	}
}

const withNoRender = createHigherOrderComponent(
	(BlockListBlock: any) => (props: tBlockListBlockProps) => {
		// @ts-ignore
		if(props?.attributes?.skaBlocksRender?.editorNoRender) {
			return (
				<BlockListBlock
					{...props}
					wrapperProps={{
						...props.wrapperProps,
						'data-ska-editor-no-render': true,
					}}
				/>
			)
		}
		return <BlockListBlock {...props} />
	},
	'withSkaBlocksEditorNoRender'
)

export default () => {
	addFilter('blocks.registerBlockType', 'ska-blocks/with-render-support', withRenderSupport, 500)
	addFilter('editor.BlockEdit', 'ska-blocks/with-render-controls', withRenderControls, 450)
	addFilter('blocks.getSaveContent.extraProps', `ska-blocks/with-render-classes`, withRenderClassNames)
	addFilter('editor.BlockListBlock', 'ska-blocks/with-no-render', withNoRender, 500)
}
