import { Switch } from '@/components/ui/switch';
import { mergeAttributes, Node } from '@tiptap/core';
import {
	NodeViewWrapper,
	ReactNodeViewRenderer,
	type ReactNodeViewProps,
} from '@tiptap/react';
import { __ } from '@wordpress/i18n';
import { Plus, Trash2 } from 'lucide-react';
import { nanoid } from 'nanoid';
import { useEffect, useRef, useState } from 'react';

type Option = { id: string; label: string };

type Attrs = {
	label: string;
	required: boolean;
	options: Option[];
};

type OptionsFieldConfig = {
	/** Node name, e.g. 'multipleChoice' */
	name: string;
	/** HTML data-type attribute, e.g. 'multiple-choice' */
	dataType: string;
	/** Badge label shown inside the card, e.g. 'Single Choice' */
	typeLabel: string;
	/** Insert command name, e.g. 'insertMultipleChoice' */
	commandName: string;
	/** Whether options use checkboxes (true) or radio circles (false) */
	isCheckbox?: boolean;
};

export function createOptionsField({
	name,
	dataType,
	typeLabel,
	commandName,
	isCheckbox = false,
}: OptionsFieldConfig) {
	return Node.create({
		name,
		group: 'block',
		atom: true,
		selectable: true,
		draggable: true,

		addAttributes() {
			return {
				label: { default: '' },
				required: { default: false },
				autoFocus: { default: false, renderHTML: () => ({}) },
				id: { default: nanoid() },
				options: {
					default: [{ id: nanoid(), label: '' }],
					parseHTML: (el) => {
						const raw = el.getAttribute('data-options');
						return raw ? JSON.parse(raw) : [{ id: nanoid(), label: '' }];
					},
					renderHTML: (attrs) => ({
						'data-options': JSON.stringify(attrs.options),
					}),
				},
			};
		},

		parseHTML() {
			return [{ tag: `div[data-type="${dataType}"]` }];
		},

		renderHTML({ HTMLAttributes }) {
			return [
				'div',
				mergeAttributes(HTMLAttributes, { 'data-type': dataType }),
			];
		},

		addNodeView() {
			return ReactNodeViewRenderer((props: ReactNodeViewProps) => (
				<OptionsFieldComponent
					{...props}
					typeLabel={typeLabel}
					isCheckbox={isCheckbox}
				/>
			));
		},

		addCommands() {
			return {
				[commandName]:
					(attrs: Partial<Attrs> = {}) =>
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
					({ chain }: any) =>
						chain()
							.insertContent({
								type: name,
								attrs: {
									label: attrs.label ?? '',
									required: attrs.required ?? false,
									options: attrs.options ?? [{ id: nanoid(), label: '' }],
									autoFocus: true,
								},
							})
							.run(),
			};
		},
	});
}

type OptionsFieldComponentProps = ReactNodeViewProps & {
	typeLabel: string;
	isCheckbox: boolean;
};

function OptionsFieldComponent({
	node,
	updateAttributes,
	typeLabel,
	isCheckbox,
}: OptionsFieldComponentProps) {
	const { label, required, options, autoFocus } = node.attrs as Attrs & {
		autoFocus: boolean;
	};
	const [attrs, setAttrs] = useState<Attrs>({ label, required, options });
	const labelRef = useRef<HTMLInputElement>(null);
	const focusIdRef = useRef<string | null>(null);

	useEffect(() => {
		if (autoFocus) {
			labelRef.current?.focus();
			updateAttributes({ autoFocus: false });
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const commit = (next: Attrs) => {
		setAttrs(next);
		updateAttributes(next);
	};

	const updateOptionLabel = (id: string, value: string) =>
		commit({
			...attrs,
			options: attrs.options.map((o) =>
				o.id === id ? { ...o, label: value } : o,
			),
		});

	const removeOption = (id: string) =>
		commit({ ...attrs, options: attrs.options.filter((o) => o.id !== id) });

	const addOption = () => {
		const id = nanoid();
		focusIdRef.current = id;
		commit({ ...attrs, options: [...attrs.options, { id, label: '' }] });
	};

	return (
		<NodeViewWrapper className="rounded border bg-gray-50 p-3">
			<div className="rounded-[9px] border border-gray-200 bg-white px-4 py-3.5 transition-colors focus-within:border-teal-400">
				<div className="mb-2.5 flex items-center">
					<span className="text-[10px] font-bold tracking-widest text-teal-500 uppercase">
						{typeLabel}
					</span>
					<div className="ml-auto flex items-center gap-1.5">
						<span className="text-[11px] text-gray-400">
							{__('Required?', 'allcoach')}
						</span>
						<Switch
							size="sm"
							checked={attrs.required ?? false}
							onCheckedChange={(v) => commit({ ...attrs, required: v })}
						/>
					</div>
				</div>

				<input
					ref={labelRef}
					value={attrs.label}
					onChange={(e) =>
						setAttrs((prev) => ({ ...prev, label: e.target.value }))
					}
					onBlur={() => updateAttributes({ label: attrs.label })}
					className="w-full border-b border-dashed border-gray-200 bg-transparent pb-1 text-[14px] font-semibold text-gray-800 outline-none placeholder:font-normal placeholder:text-gray-400 focus:border-teal-400"
					placeholder={__('Question…', 'allcoach')}
				/>

				<div className="mt-2 flex flex-col gap-1.5">
					{attrs.options.map((opt) => (
						<div key={opt.id} className="group/opt flex items-center gap-2">
							<div
								className={`size-4 shrink-0 border-2 border-gray-200 ${isCheckbox ? 'rounded' : 'rounded-full'}`}
							/>
							<input
								ref={(el) => {
									if (el && focusIdRef.current === opt.id) {
										el.focus();
										focusIdRef.current = null;
									}
								}}
								value={opt.label}
								onChange={(e) => updateOptionLabel(opt.id, e.target.value)}
								placeholder={__('Option…', 'allcoach')}
								className="flex-1 border-b border-dashed border-gray-200 bg-transparent pb-0.5 text-[13px] text-gray-700 outline-none placeholder:text-gray-400 focus:border-teal-400"
							/>
							{attrs.options.length > 1 && (
								<button
									type="button"
									onClick={() => removeOption(opt.id)}
									className="flex size-5 shrink-0 items-center justify-center rounded text-gray-300 opacity-0 transition-opacity group-hover/opt:opacity-100 hover:text-red-500"
								>
									<Trash2 className="size-3" />
								</button>
							)}
						</div>
					))}
					<button
						type="button"
						onClick={addOption}
						className="mt-1 flex w-fit items-center gap-1 text-[12px] text-teal-600 hover:text-teal-700"
					>
						<Plus className="size-3" />
						{__('Add option', 'allcoach')}
					</button>
				</div>
			</div>
		</NodeViewWrapper>
	);
}
