import React, { useCallback, useRef } from 'react';
import {
  KsGrid,
  Icon,
  KsDeleteButton,
  StatusMessage,
  KsFileUpload,
  KsButton,
} from '@knapsack/design-system';
import arrayMove from 'array-move';
import cn from 'classnames';
import { useDropzone, DropzoneOptions } from 'react-dropzone';
import { Slice } from './types';
import { uploadFile } from '../../../data';
import { InlineEditText } from '../../../components/inline-edit';
import { useKsDragDrop } from '../../../hooks';
import './image-slice.scss';

type Image = {
  caption?: string;
  src: string;
};

type Data = {
  imageSize?: 's' | 'm' | 'l';
  images?: Image[];
};

type Props = {
  image: Image;
  showControls: boolean;
  index: number;
  handleCaptionSave: (text: string) => void;
  move: (from: number, to: number) => void;
  handleDelete: () => void;
};

const ImageSliceImage: React.FC<Props> = ({
  image,
  index,
  showControls,
  handleCaptionSave,
  handleDelete,
  move,
}: Props) => {
  const ref = useRef<HTMLDivElement>(null);
  const { isDragging } = useKsDragDrop({
    ref,
    dragTypeId: 'image-slice-image',
    canDrag: showControls,
    index,
    handleDrop: ({ dragIndex }) => {
      move(dragIndex, index);
    },
  });

  return (
    <div
      style={{ opacity: isDragging ? 0 : 1 }}
      ref={ref}
      className="ks-image-slice__image"
    >
      <div
        className={cn('ks-image-slice__image__img-wrapper', {
          'ks-image-slice__image__img-wrapper--can-edit': showControls,
        })}
      >
        {showControls && (
          <div className="ks-image-slice__image__controls">
            <div className="ks-image-slice__image__controls__handle">
              <Icon symbol="drag-handle" size="s" />
            </div>
            <div className="ks-image-slice__image__controls__open-external">
              <KsButton
                kind="icon"
                icon="external-link"
                flush
                handleTrigger={() => {
                  window.open(image.src, '_blank');
                }}
              >
                Open in New Window
              </KsButton>
            </div>
            <div className="ks-image-slice__image__controls__delete-btn">
              <KsDeleteButton flush size="s" handleTrigger={handleDelete} />
            </div>
            <div
              className="ks-image-slice__image__controls__caption"
              title={`Image Caption: ${image.caption}`}
            >
              <InlineEditText
                text={image.caption}
                handleSave={handleCaptionSave}
                noWrap
              />
            </div>
          </div>
        )}
        <img src={image.src} alt={image.caption} />
      </div>
    </div>
  );
};

async function handleFiles(
  files: File[],
): Promise<{ src: string; caption: string }[]> {
  const uploadedFiles = await Promise.all(
    files.map(async file => {
      const results = await uploadFile(file);
      if (!results.ok) {
        console.error('uh oh!', { results, file });
      }
      return results.data;
    }),
  );

  return uploadedFiles.map(file => {
    return {
      src: file.publicPath,
      caption: file.originalName,
    };
  });
}

const ImageSlice = ({
  canEdit,
  setSliceData,
  data = {},
}: import('./types').SliceRenderParams<Data>): JSX.Element => {
  // const [localData, setData] = useValueDebounce(data, setSliceData);
  // const [files, setFiles] = useState<
  //   ({
  //     preview: string;
  //   } & File)[]
  // >([]);
  const { images = [], imageSize = 'm' } = data;

  const onDrop = useCallback<DropzoneOptions['onDrop']>(async acceptedFiles => {
    // setFiles(
    //   acceptedFiles.map(file => ({
    //     ...file,
    //     preview: URL.createObjectURL(file),
    //   })),
    // );
    const uploadedImages = await handleFiles(acceptedFiles);
    // The extra robust data.images checks are the result of
    // having just [...uploadedImages, ...data.images] kept
    // resulting in "undefined" errors.
    setSliceData({
      images:
        images?.length > 0
          ? [...uploadedImages, ...images]
          : [...uploadedImages],
    });
  }, []);

  const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
    onDrop,
    accept: ['image/*'],
    multiple: true,
    noClick: true,
    noKeyboard: true,
  });
  // if (images.length === 0) return <h5>Not enough data to render...</h5>;
  const rootAttributes = canEdit ? getRootProps() : {};
  const inputProps = getInputProps();

  const classes = cn('ks-image-slice', {
    'ks-image-slice--dragging': isDragActive,
  });

  if (images?.length < 1 && !canEdit) return null;

  return (
    <div className={classes} {...rootAttributes}>
      {canEdit && isDragActive && (
        <div className="ks-image-slice__dropzone">
          <p>Drop images here to upload...</p>
          <input {...inputProps} />
        </div>
      )}
      {images?.length > 0 ? (
        <KsGrid itemSize={imageSize}>
          {images.map((image, index) => (
            <ImageSliceImage
              image={image}
              key={`${image.src}-${canEdit}`}
              index={index}
              showControls={canEdit}
              move={(from, to) => {
                setSliceData({
                  images: arrayMove(images, from, to),
                });
              }}
              handleDelete={() => {
                setSliceData({
                  images: images.filter((img, i) => index !== i),
                });
              }}
              handleCaptionSave={text => {
                setSliceData({
                  images: images.map((img, i) => {
                    if (index !== i) return img;
                    return {
                      ...img,
                      caption: text,
                    };
                  }),
                });
              }}
            />
          ))}
        </KsGrid>
      ) : (
        <div
          className={cn('ks-image-slice__no-images-msg', {
            'ks-image-slice__no-images-msg__drag-active': isDragActive,
          })}
        >
          <h3>Image Grid Slice</h3>
          <p>No images have been added yet.</p>
          <p>Add images by dropping them here, or via the slice settings.</p>
        </div>
      )}
    </div>
  );
};

export const imageSlice: Slice<Data> = {
  id: 'image-slice',
  title: 'Image Grid',
  description: 'Multiple images with captions laid out in a grid.',
  render: props => <ImageSlice {...props} />,
  renderEditForm: ({ setSliceData, data }) => {
    return (
      <>
        <div className="ks-image-slice__edit-warning">
          <StatusMessage
            type="warning"
            message="Image uploading currently only works on localhost."
          />
        </div>
        <KsFileUpload
          buttonLabel="Select Images to Upload"
          accept="image/*"
          multiple
          buttonProps={{ isFullWidth: true }}
          handleChange={async e => {
            const files: File[] = Array.from(e.target.files);

            if (!files) return;
            const uploadedImages = await handleFiles(files);

            // The extra robust data.images checks are the result of
            // having just [...uploadedImages, ...data.images] kept
            // resulting in "undefined" errors.
            setSliceData({
              images:
                data?.images?.length > 0
                  ? [...uploadedImages, ...data.images]
                  : [...uploadedImages],
            });
          }}
        />
      </>
    );
  },
  schema: {
    type: 'object',
    required: [],
    properties: {
      imageSize: {
        title: "Image's Display Size",
        type: 'string',
        enum: ['s', 'm', 'l'],
        enumNames: ['small', 'medium', 'large'],
        default: 'm',
      },
    },
  },
};
