/**
 * @file CustomFileInput.tsx - Custom styled file input that replaces the browser's native file picker UI with a Bootstrap-styled input group.
 * Features localized button text, validation feedback (valid/invalid borders and icons), and support for single or multiple file selection.
 * A hidden native `<input type="file" />` overlays the styled group to capture clicks and file selections.
 * Essentially just the normal Bootstrap file picker button but completely custom to allow localized text.
 */

import {
  type ChangeEvent,
  type FC,
  type RefObject,
  useEffect,
  useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import './CustomFileInput.css';

/**
 * Props for the CustomFileInput component.
 */
interface CustomFileInputProps {
  /** Ref forwarded to the hidden native file input element */
  ref: RefObject<HTMLInputElement | null>;

  /** When true, allows the user to select more than one file */
  multiple?: boolean;

  /** Comma-separated MIME types or extensions the file dialog should accept */
  accept: string;

  /** Disables the input and applies not-allowed cursor styling */
  disabled?: boolean;

  /** Marks the input as required for form validation */
  required?: boolean;

  /** When true, triggers visual validation feedback (valid/invalid border and icons) */
  validated?: boolean;
}

/**
 * Custom file input component with a Bootstrap-styled browse button and status text.
 * The status text updates to show "No file chosen", the selected file name, or a count of selected files (when multiple).
 * Validation state is applied via CSS classes that mirror Bootstrap's is-valid and is-invalid styling.
 */
export const CustomFileInput: FC<CustomFileInputProps> = ({
  ref,
  multiple,
  accept,
  disabled,
  required,
  validated,
}) => {
  const { t } = useTranslation(undefined, {
    keyPrefix: 'components.custom_file_input',
  });
  // Default placeholder text varies based on single vs. multiple file mode
  const defaultStatusText = multiple
    ? t('placeholder.none.multiple')
    : t('placeholder.none.single');

  // Tracks the text shown next to the browse button (file name, count, or placeholder)
  const [statusText, setStatusText] = useState(defaultStatusText);
  // Update status text when the user selects files
  const onFileChange = (event: ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files;

    if (!files || files.length === 0) {
      setStatusText(defaultStatusText);
      return;
    }

    if (files.length === 1) {
      setStatusText(files[0].name);
      return;
    }

    setStatusText(t('placeholder.some.multiple', { file_count: files.length }));
  };

  // Re-check native validity whenever the parent sets validated to true
  const [valid, setValid] = useState(false);
  useEffect(() => {
    if (validated) {
      checkValidity();
    }
  }, [validated]);
  const checkValidity = () => {
    setValid(ref.current?.checkValidity() as boolean);
  };

  return (
    <div
      className={`custom-file-input-group ${validated ? `is-${valid ? 'valid' : 'invalid'}` : ''}`}
    >
      <input
        ref={ref}
        type={'file'}
        multiple={multiple}
        accept={accept}
        disabled={disabled}
        onChange={(event) => {
          onFileChange(event);
          checkValidity();
        }}
        required={required}
      />
      <div className={'input-group'}>
        <span className={'input-group-text'}>
          {t('buttons.browse.button_text')}...
        </span>
        <input
          type={'text'}
          className={'form-control'}
          value={statusText}
          readOnly
          tabIndex={-1}
        />
      </div>
    </div>
  );
};
