import { useCallback, useMemo, useState } from 'react';

import type { FC, ReactNode } from 'react';
import type { CloseDialogBox } from '../DialogBox';
import type { ImageCrop } from './types';

import useIsLargeScreen from '~/src/hooks/useIsLargeScreen';
import { cropImage } from '~/src/lib/utils/image';
import Clickable from '../Clickable';
import DialogBox from '../DialogBox';
import { DialogBoxHeader } from '../DialogBox/DialogBoxHeader';
import { InputLabelDescription } from '../InputLabel';
import RangeSlider from '../RangeSlider';
import Text from '../Text';
import CropImage from './CropImage';

export interface CropImageResult {
  crop: ImageCrop;
  file: File;
  src: string;
}

export type CropImageDialogOnDone = (params: {
  result: CropImageResult;
  close: CloseDialogBox;
}) => void;

const CropImageDialog: FC<{
  onClose: () => void;
  title: string;
  originalFile: File;
  description: ReactNode;
  onDone: CropImageDialogOnDone;
}> = ({ onClose, description, title, onDone, originalFile }) => {
  const [crop, setCrop] = useState<ImageCrop>();
  const [zoom, setZoom] = useState(1);
  const isLargeScreen = useIsLargeScreen();

  const imageSrc = useMemo(
    () => URL.createObjectURL(originalFile),
    [originalFile]
  );

  return (
    <DialogBox
      fillViewport={!isLargeScreen}
      onClose={onClose}
      maxHeight={600}
      renderContent={useCallback(
        ({ close }) => {
          return (
            <>
              <DialogBoxHeader
                title={title}
                background={false}
                renderRight={({ textProps }) => (
                  <Clickable
                    testId="submitImage"
                    onClick={async () => {
                      if (!crop) return;

                      const { blob, src } = await cropImage(originalFile, crop);

                      const file = new File([blob], originalFile.name, {
                        type: originalFile.type,
                      });

                      onDone({
                        close,

                        result: {
                          crop,
                          file,
                          src,
                        },
                      });
                    }}
                  >
                    <Text {...textProps}>Done</Text>
                  </Clickable>
                )}
              />
              <CropImage
                src={imageSrc}
                zoom={zoom}
                onZoomChange={({ zoom }) => {
                  setZoom(zoom);
                }}
                onChange={({ crop }) => {
                  setCrop(crop);
                }}
              />
              <RangeSlider
                margin="1.7rem 1.7rem 0"
                min={1}
                max={3}
                value={zoom}
                onChange={({ value }) => {
                  setZoom(value);
                }}
              />
              {description && (
                <InputLabelDescription
                  value={description}
                  padding="0 1.7rem 1.7rem"
                  noSelection
                />
              )}
            </>
          );
        },
        [crop, zoom, imageSrc, close, originalFile]
      )}
    />
  );
};

export default CropImageDialog;
