// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
import {useEffect, useState} from "react";
import styles from "./TextField.module.css";

/**
 * A styled text input that updates its value **in real time** at every keystroke.
 *
 * Automatically toggles between read-only and editable modes to integrate with
 * drag-based UIs (like React Flow). Calls `onCommit` when editing is completed.
 *
 * @param props - Component properties.
 * @param props.value - The current text input value.
 * @param props.setValue - Callback invoked on every keystroke to update the value.
 * @param props.onCommit - Callback invoked when editing is finalized (on blur or Enter).
 * @param props.placeholder - Optional placeholder text displayed when the input is empty.
 * @param props.className - Optional additional CSS class names.
 * @param props.id - Optional unique HTML `id` for the input element.
 * @param props.ariaLabel - Optional ARIA label for accessibility.
 * @param props.invalid - If true, applies error styling to indicate invalid input.
 *
 * @returns A styled `<input>` element that updates its value in real time.
 */
export function RealtimeTextField({
  value = "",
  setValue,
  onCommit,
  placeholder,
  className,
  id,
  ariaLabel,
  invalid = false,
} : {
  value: string,
  setValue: (value: string) => void,
  onCommit: () => void,
  placeholder?: string,
  className?: string,
  id?: string,
  ariaLabel?: string,
  invalid?: boolean,
}) {
  /** Tracks whether the input is currently read-only (for drag compatibility). */
  const [readOnly, setReadOnly] = useState(true);

  /** Finalizes editing and calls `onCommit` when the user exits the field. */
  const updateData  = () => {
    setReadOnly(true);
    onCommit();
  };

  /** Handles the Enter key — commits the input by triggering a blur event. */
  const updateOnEnter = (event: React.KeyboardEvent<HTMLInputElement>) => { 
    if (event.key === "Enter") 
      (event.target as HTMLInputElement).blur(); };

  return <input
    type={"text"}
    placeholder={placeholder}
    value={value}
    onChange={(e) => setValue(e.target.value)}
    onFocus={() => setReadOnly(false)}
    onBlur={updateData}
    onKeyDown={updateOnEnter}
    readOnly={readOnly}
    id={id}
    // ReactFlow uses the "drag" / "nodrag" classes to enable / disable dragging of nodes
    className={`${readOnly ? "drag" : "nodrag"} flex-1 ${styles.textField} ${invalid ? styles.invalid : ""} ${className}`}
    aria-label={ariaLabel}
  />;
}

/**
 * A styled text input that updates its value **only on commit** (when the user
 * presses Enter or clicks outside the input).
 *
 * Internally wraps `RealtimeTextField` and buffers input changes locally,
 * calling `setValue` only once editing is complete.
 *
 * @param props - Component properties.
 * @param props.value - The current text input value.
 * @param props.setValue - Callback invoked when the user commits the change.
 * @param props.placeholder - Optional placeholder text displayed when the input is empty.
 * @param props.className - Optional additional CSS class names.
 * @param props.id - Optional unique HTML `id` for the input element.
 * @param props.ariaLabel - Optional ARIA label for accessibility.
 * @param props.invalid - If true, applies error styling to indicate invalid input.
 *
 * @returns A styled `<input>` element that updates its parent state only on commit.
 */
export function TextField({
  value = "",
  setValue,
  placeholder,
  className,
  id,
  ariaLabel,
  invalid = false,
} : {
  value: string,
  setValue: (value: string) => void,
  placeholder?: string,
  className?: string,
  id?: string,
  ariaLabel?: string,
  invalid?: boolean,
}) {
  const [inputValue, setInputValue] = useState(value);

  useEffect(() => {
    setInputValue(value);
  }, [value]);

  const onCommit = () => setValue(inputValue);

  return <RealtimeTextField
    placeholder={placeholder}
    value={inputValue}
    setValue={setInputValue}
    onCommit={onCommit}
    id={id}
    className={className}
    ariaLabel={ariaLabel}
    invalid={invalid}
  />;
}
