/**
 * @file FileUploadDropzone.tsx - Drag-and-drop file upload component using react-dropzone.
 * Accepts a single file matching the configured UPLOAD_ACCEPTED_FILE_EXTENSIONS.
 * Exposes an imperative open() method via forwardRef/useImperativeHandle so parent components can programmatically trigger the file picker dialog (e.g., from the upload toolbar button or hotkey).
 */

import {
  type ForwardRefRenderFunction,
  forwardRef,
  useCallback,
  useImperativeHandle,
} from 'react';
import { toast } from 'react-toastify';
import { useDropzone } from 'react-dropzone';
import { Card, Spinner } from 'react-bootstrap';
import { UPLOAD_ACCEPTED_FILE_EXTENSIONS } from '../../../../../constants.ts';
import { useTranslation } from 'react-i18next';

/**
 * Imperative handle exposed to parent components via ref to programmatically open the file dialog.
 */
export type FileUploadDropzoneHandle = {
  open: () => void;
};

/**
 * Props for the FileUploadDropzone component.
 */
interface FileUploadDropzoneProps {
  /** Callback invoked with the accepted File when a valid file is dropped or selected */
  onFileAccepted: (file: File) => void;

  /** Whether an upload operation is currently in progress (disables the dropzone) */
  processing: boolean;
}

/**
 * Drag-and-drop file upload area for uploading new documents to a work item. Uses forwardRef to expose click function to calling component.
 *
 * @param onFileAccepted Function to execute when a file has been accepted
 * @param processing Whether the upload operation is currently processing
 */
const FileUploadDropzoneInner: ForwardRefRenderFunction<
  FileUploadDropzoneHandle,
  FileUploadDropzoneProps
> = ({ onFileAccepted, processing }, ref) => {
  // Validates dropped files and calls onFileAccepted
  const onDrop = useCallback(
    (acceptedFiles: File[], fileRejections: any[]) => {
      if (fileRejections.length) {
        toast.error(t('callbacks.on_drop.errors.file_type_unsupported'));
        return;
      }

      if (acceptedFiles.length) {
        onFileAccepted(acceptedFiles[0]);
      }
    },
    [onFileAccepted]
  );

  // Setup dropzone functionality
  const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
    onDrop,
    multiple: false,
    accept: Object.fromEntries(
      UPLOAD_ACCEPTED_FILE_EXTENSIONS.map(({ mimeType, extensions }) => [
        mimeType,
        extensions,
      ])
    ),
    noClick: false,
    disabled: processing,
  });

  // Expose open() to parent via ref
  useImperativeHandle(ref, () => ({ open }));

  const { t } = useTranslation(undefined, {
    keyPrefix:
      'components.processing.details_folder_panel.sections.folder_section.components.file_upload_dropzone',
  });

  return (
    <Card
      {...getRootProps()}
      className={`text-center border border-secondary-subtle ${isDragActive || processing ? 'bg-light' : ''}`}
      style={{ cursor: processing ? '' : 'pointer' }}
      ref={(element) => {
        if (element) {
          element.style.setProperty('border-style', 'dashed', 'important');
        }
      }}
    >
      <input {...getInputProps()} disabled={processing} />
      <span className={'text-muted p-3'}>
        {t('cards.drag_drop.body.instruction_text')}
      </span>
      {processing && (
        <div
          className={
            'position-absolute top-0 left-0 w-100 h-100 bg-light d-flex justify-content-center align-items-center z-1'
          }
        >
          <Spinner
            size={'sm'}
            animation={'border'}
            role={'status'}
            variant={'secondary'}
            aria-hidden={'true'}
            className={'me-2'}
          />
          <span className={'text-muted'}>
            {t('cards.drag_drop.body.uploading_text')}...
          </span>
        </div>
      )}
    </Card>
  );
};

export const FileUploadDropzone = forwardRef(FileUploadDropzoneInner);
