import * as stylex from "@stylexjs/stylex";
import {
	type Ref,
	memo,
	useCallback,
	useEffect,
	useImperativeHandle,
	useRef,
} from "react";
import { controlColor } from "./theme.stylex";
import { font, size } from "./tokens.stylex";

/**
 * Properties and some behavior of this TextArea is based on the Text Field of MUI:
 * https://mui.com/material-ui/react-text-field/
 */
export interface TextAreaProps {
	// Commonly used text props
	name?: string;
	placeholder?: string;
	disabled?: boolean;
	required?: boolean;
	maxLength?: number;
	minLength?: number;
	title?: string;
	autoFocus?: boolean;
	defaultValue?: string;

	/** If set, height will be 100% */
	fullHeight?: boolean;

	/** Auto-grow is default. However, it is only best-effort (only works in browsers that support `field-sizing`). This prop turns it off completely. */
	noAutoGrow?: boolean;

	/** `value` and `onChange` are optional because we want to be able to use the control in an uncontrolled manner as well (for example, in forms) */
	value?: string;
	onChange?: (value: string) => void;

	ref?: Ref<{ focus: () => void }>;
}

const styles = stylex.create({
	area: {
		resize: "vertical",

		borderWidth: "1px",
		borderStyle: "solid",

		borderColor: {
			default: controlColor.inputBorder,
			":focus": controlColor.inputActiveBorder,
			// https://web.dev/articles/user-valid-and-user-invalid-pseudo-classes
			":user-invalid": controlColor.inputInvalidBorder,
			":disabled": controlColor.inputDisabledBorder,
		},

		borderRadius: 0,

		color: {
			default: controlColor.inputColor,
			":focus": controlColor.inputActiveColor,
			":disabled": controlColor.inputDisabledColor,
		},

		padding: `${size.px2} ${size.px3}`,
		fontSize: size.rem4,
		fontWeight: 400,
		fontFamily: font.main,

		width: "100%",

		"::placeholder": {
			color: controlColor.inputPlaceholderColor,
		},

		background: {
			default: controlColor.inputBackground,
			":focus": controlColor.inputActiveBackground,
			":disabled": controlColor.inputDisabledBackground,
		},

		cursor: {
			":disabled": "not-allowed",
		},
		outline: {
			":focus": "none",
		},

		fieldSizing: "content",
	},

	fullHeight: {
		height: "100%",
	},

	noAutoGrow: {
		fieldSizing: "content",
	},
});

/**
 * @remarks Currently does not support submitting a form by pressing `Ctrl+Enter`.
 * TODO: Support this if the need arises: https://stackoverflow.com/q/1684196
 */
export default memo(function TextArea(props: TextAreaProps) {
	const onChange = useCallback(
		(e: React.ChangeEvent<HTMLTextAreaElement>) => {
			props.onChange?.(e.target.value);
		},
		[props.onChange],
	);

	const innerRef = useRef<HTMLTextAreaElement>(null);

	useImperativeHandle(
		props.ref,
		() => ({
			focus: () => innerRef.current?.focus(),
		}),
		[],
	);

	useEffect(() => {
		const r = innerRef.current;
		if (!r) {
			return;
		}

		const handler = (e: KeyboardEvent) => {
			if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
				const target = e.currentTarget as HTMLTextAreaElement | null;
				// If there are any issues, see: https://gist.github.com/KacperKozak/9736160
				// When using .submit(), this error is thrown:
				// > A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead.
				target?.form?.requestSubmit();
				e.stopPropagation();
				e.preventDefault();
			}
		};

		r.addEventListener("keydown", handler);
		return () => r.removeEventListener("keydown", handler);
	}, []);

	return (
		<textarea
			{...stylex.props(
				styles.area,
				props.fullHeight && styles.fullHeight,
				props.noAutoGrow && styles.noAutoGrow,
			)}
			placeholder={props.placeholder}
			name={props.name}
			required={props.required}
			disabled={props.disabled}
			minLength={props.minLength}
			maxLength={props.maxLength}
			title={props.title}
			// biome-ignore lint/a11y/noAutofocus: We're just passing it down
			autoFocus={props.autoFocus}
			defaultValue={props.defaultValue}
			value={props.value}
			onChange={onChange}
			ref={innerRef}
		/>
	);
});
