import { Spinner } from '@wordpress/components'
import React, { useState } from 'react'
import { __, sprintf } from '@wordpress/i18n'
import { useRestAPI } from '../../hooks/useRestAPI'
import { useSnippetsList } from '../../hooks/useSnippetsList'
import { createSnippetObject, getSnippetDisplayName, getSnippetEditUrl } from '../../utils/snippets/snippets'
import { Button } from '../common/Button'
import { useSnippetForm } from '../../hooks/useSnippetForm'
import { SubmitButton } from '../common/SubmitButton'
import { Tooltip } from '../common/Tooltip'
import { ConditionEditor } from '../ConditionEditor'
import { DismissibleNotice } from '../common/DismissableNotice'
import type { Snippet } from '../../types/Snippet'
import type { Dispatch, FormEventHandler, PropsWithChildren, SetStateAction } from 'react'

interface ModalFooterProps {
	onClose: VoidFunction
	isSubmitting: boolean
}

const ModalFooter: React.FC<ModalFooterProps> = ({ onClose, isSubmitting }) =>
	<div className="modal-footer">
		<Button link onClick={onClose}>
			{__('Cancel', 'code-snippets')}
		</Button>

		<div>
			{isSubmitting && <Spinner />}

			<SubmitButton primary large disabled={isSubmitting} text={__('Save Condition', 'code-snippets')} />
		</div>
	</div>

interface ModalUpperProps {
	onClose: VoidFunction
	condition: Snippet
	isSubmitting: boolean
	setCondition: Dispatch<SetStateAction<Snippet>>
}

const ModalUpper: React.FC<ModalUpperProps> = ({ onClose, condition, isSubmitting, setCondition }) =>
	<>
		<div className="modal-content-top">
			<label htmlFor="condition-name">
				{__('Condition Name', 'code-snippets')}
				<Tooltip inline end>
					{__('Give a name to this condition so you can reuse it on other snippets, or leave blank for an autogenerated name.', 'code-snippets')}
				</Tooltip>
			</label>

			{condition.id
				? <a href={getSnippetEditUrl({ id: condition.id })} target="_blank" rel="noreferrer">
					{__('Open full editor', 'code-snippets')}
				</a>
				: <Button link onClick={() => onClose()}>
					{__('Apply existing condition', 'code-snippets')}
				</Button>}
		</div>

		<input
			id="condition-name"
			type="text"
			disabled={isSubmitting}
			className="condition-name-input"
			placeholder={__('Add a name for this condition.', 'code-snippets')}
			value={condition.name}
			onChange={event => setCondition(previous => ({ ...previous, name: event.target.value }))}
		/>
	</>

const createInitialCondition = (snippet: Snippet): Snippet =>
	createSnippetObject({
		name: '',
		tags: snippet.tags,
		scope: 'condition',
		active: false,
		conditions: {
			_0: {
				_0: {}
			}
		}
	})

interface ModalFormProps extends Pick<EditConditionFormProps, 'setSelectedConditionId' | 'onSave'> {
	condition: Snippet
	setHasError: Dispatch<SetStateAction<boolean>>
	setIsSubmitting: Dispatch<SetStateAction<boolean>>
}

const ModalForm: React.FC<PropsWithChildren<ModalFormProps>> = ({
	onSave,
	children,
	condition,
	setHasError,
	setIsSubmitting,
	setSelectedConditionId
}) => {
	const { snippetsAPI: { update } } = useRestAPI()
	const { snippet, setSnippet } = useSnippetForm()
	const { snippetsList, refreshSnippetsList } = useSnippetsList()

	const handleSubmit: FormEventHandler<HTMLFormElement> = event => {
		event.preventDefault()
		setIsSubmitting(true)
		let success = false

		const name = '' === condition.name.trim()
			// translators: %s: snippet display name.
			? sprintf(__('Condition for "%s"', 'code-snippets'), getSnippetDisplayName(snippet))
			: condition.name

		const duplicateNames = snippetsList?.filter(snippet =>
			snippet.name.startsWith(name) && snippet.id !== condition.id).length

		// translators: %s: condition name, %d: duplicate number.
		update({ ...condition, name: duplicateNames ? sprintf(__('%s (%d)', 'code-snippets'), name, duplicateNames) : name })
			.then(result => {
				setSnippet(previous => ({ ...previous, conditionId: result.id }))
				setSelectedConditionId(result.id)
				success = true
				return refreshSnippetsList()
			})
			.catch((error: unknown) => {
				console.error('Error creating condition', error)
				setHasError(true)
				return refreshSnippetsList()
			})
			.finally(() => {
				setIsSubmitting(false)

				if (success) {
					onSave()
				}
			})
	}

	return <form className="modal-form" onSubmit={handleSubmit}>{children}</form>
}

export interface EditConditionFormProps {
	onSave: VoidFunction
	onCancel: VoidFunction
	condition?: Snippet
	setSelectedConditionId: Dispatch<SetStateAction<number>>
}

export const EditConditionForm: React.FC<EditConditionFormProps> = ({
	onSave,
	onCancel,
	condition: initialCondition,
	setSelectedConditionId
}) => {
	const { snippet } = useSnippetForm()
	const { snippetsList } = useSnippetsList()
	const [hasError, setHasError] = useState(false)
	const [condition, setCondition] = useState<Snippet>(() => initialCondition ?? createInitialCondition(snippet))
	const [isSubmitting, setIsSubmitting] = useState(false)

	const hasOtherAttachedSnippets = !!initialCondition?.id && snippetsList?.some(({ id, conditionId }) =>
		id !== snippet.id && conditionId === initialCondition.id)

	return (
		<ModalForm {...{ condition, setIsSubmitting, setHasError, setSelectedConditionId, onSave }}>
			<div className="modal-content">
				<ModalUpper
					onClose={onCancel}
					condition={condition}
					isSubmitting={isSubmitting}
					setCondition={setCondition}
				/>

				{hasOtherAttachedSnippets
					? <div className="notice notice-warning"><p>
						<strong>{__('Heads-up!', 'code-snippets')}</strong>{' '}
						{__('This condition is used by other snippets. Changes you make here will affect all snippets using this condition.', 'code-snippets')}
					</p></div> : null}

				<ConditionEditor condition={condition} setCondition={setCondition} />

				{hasError
					? <DismissibleNotice className="notice-error" onDismiss={() => setHasError(false)}>
						<p>{__('An unknown error occurred. Please try again later', 'code-snippets')}</p>
					</DismissibleNotice> : null}
			</div>

			<ModalFooter onClose={onCancel} isSubmitting={isSubmitting} />
		</ModalForm>
	)
}
