import React, { forwardRef, Ref, useCallback, useEffect, useState } from "react";

import {
  Box,
  ButtonBase,
  Dialog,
  FormHelperText,
  Grid2 as Grid,
  Stack,
  Typography,
  Zoom,
} from "@mui/material";

import { useCardContext } from "../../contexts/CardContext";
import { useI18n } from "../../contexts/I18nContext";

import { CardFieldBaseProps } from "./shared";

export interface ImageDisplayProps {
  src: string;
  alt: string;
}

export const ImageDisplay: React.FC<ImageDisplayProps> = ({ src, alt }) => {
  const [openLightbox, setOpenLightbox] = useState(false);

  const Transition = forwardRef(function Transition(
    props: { children: React.ReactElement },
    ref: Ref<unknown>,
  ) {
    return <Zoom ref={ref} in={openLightbox} {...props} />;
  });

  return (
    <>
      <ButtonBase
        disableRipple
        sx={{ alignSelf: "baseline" }}
        onClick={() => setOpenLightbox((open) => !open)}
      >
        <Box
          alt={alt}
          component="img"
          src={src}
          sx={{
            display: "block",
            width: "auto",
            height: "100%",
            maxHeight: "200px",
            maxWidth: "200px",
            objectFit: "cover",
            borderRadius: 2,
            borderColor: "divider",
            my: 2,
            transition: "transform 150ms ease-out",
            "&:hover": { transform: "scale(1.05)" },
          }}
        />
      </ButtonBase>

      {openLightbox && (
        <Dialog
          fullWidth
          maxWidth="lg"
          open={openLightbox}
          PaperProps={{
            sx: { backgroundColor: "transparent", boxShadow: "none" },
          }}
          TransitionComponent={Transition}
          onClose={() => setOpenLightbox(false)}
        >
          <Box
            alt={alt}
            component="img"
            src={src}
            sx={{
              width: "100%",
              height: "auto",
              maxHeight: "90vh",
              objectFit: "contain",
            }}
            onClick={() => setOpenLightbox(false)}
          />
        </Dialog>
      )}
    </>
  );
};

export interface CardFieldImageProps
  extends Omit<CardFieldBaseProps, "fallbackPredicate">,
    React.PropsWithChildren {
  type: "image";
  value?: string;
}

export const CardFieldImage: React.FC<Omit<CardFieldImageProps, "type">> = ({
  fallback,
  label,
  formName,
  value: defaultValue,
  required = false,
  isDisabled = false,
  size = "grow",
  isReadable = true,
  helperText,
}) => {
  const { isCompact, isEditing } = useCardContext();
  const { t } = useI18n();

  const [selectedFile, setSelectedFile] = useState<File>();
  const [preview, setPreview] = useState<string>();

  useEffect(() => {
    if (selectedFile == null) {
      setPreview(undefined);
      return;
    }

    const objectUrl = URL.createObjectURL(selectedFile);
    setPreview(objectUrl);

    return () => URL.revokeObjectURL(objectUrl);
  }, [selectedFile]);

  const handleFileChange = useCallback(
    ({ target: { files } }: React.ChangeEvent<HTMLInputElement>) => {
      if (!files || files.length === 0) {
        setSelectedFile(undefined);
        return;
      }

      if (files.length === 1) {
        setSelectedFile(files[0]);
      } else {
        console.error("[CARD_FIELD_IMAGE]", t("Multiple files selected, this is not supported."));
        setSelectedFile(undefined);
      }
    },
    [setSelectedFile, t],
  );

  return (
    <Grid size={size}>
      {isEditing ? (
        <Stack
          component="figure"
          direction={isCompact ? "row" : "column"}
          justifyContent={isCompact ? "space-between" : "flex-start"}
          spacing={0.5}
          sx={{ m: "unset !important" }}
        >
          <Typography color="grey.600" component="figcaption" variant="subtitle2">
            {label}
          </Typography>

          <input
            accept="image/*"
            disabled={isDisabled}
            name={formName}
            required={required}
            type="file"
            onChange={handleFileChange}
          />

          {preview && <ImageDisplay alt={t("preview")} src={preview} />}
          {helperText != null && <FormHelperText>{helperText}</FormHelperText>}
        </Stack>
      ) : (
        isReadable && (
          <Stack
            component="figure"
            direction={isCompact ? "row" : "column"}
            justifyContent={isCompact ? "space-between" : "flex-start"}
            spacing={0.5}
            sx={{ m: "unset !important" }}
          >
            <Typography
              color="grey.600"
              component="figcaption"
              fontWeight={600}
              variant="subtitle2"
            >
              {label}
            </Typography>

            {typeof defaultValue === "string" ? (
              <ImageDisplay alt={label} src={defaultValue} />
            ) : (
              <Typography>{fallback ?? t("No image available")}</Typography>
            )}
          </Stack>
        )
      )}
    </Grid>
  );
};

export default CardFieldImage;
