import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';

import type { KeyboardEvent, JSX } from 'react';

import { parseSrcSet, parseStyleString } from '@redocly/theme/core/utils';
import { useModalScrollLock } from '@redocly/theme/core/hooks';

export type ImageProps = {
  src?: string;
  srcSet?: string;
  alt?: string;
  className?: string;
  width?: string | number;
  height?: string | number;
  border?: string;
  withLightbox?: boolean;
  lightboxStyle?: React.CSSProperties | string;
  style?: React.CSSProperties | string;
};

export function Image(props: ImageProps): JSX.Element {
  const { src, srcSet, alt, className, width, height, border, style, withLightbox, lightboxStyle } =
    props;

  const lightboxContainerRef = useRef<HTMLDivElement>(null);
  const [lightboxImage, setLightboxImage] = useState<string | undefined>(undefined);
  const parsedSourceSetMap = useMemo(() => {
    return srcSet ? parseSrcSet(srcSet) : new Map();
  }, [srcSet]);

  const handleLightboxKeyDown = useCallback((e: KeyboardEvent) => {
    e.stopPropagation();
    if (e.key === 'Escape') {
      setLightboxImage(undefined);
    }
  }, []);

  const handleImageClick = useCallback(
    (src: string) => {
      if (!withLightbox || lightboxImage) {
        return;
      }
      setLightboxImage(src);
    },
    [withLightbox, lightboxImage],
  );

  const handleCloseLightbox = useCallback(() => {
    setLightboxImage(undefined);
  }, []);

  useModalScrollLock(!!lightboxImage);
  useEffect(() => {
    if (lightboxImage) {
      lightboxContainerRef.current?.focus();
    }
  }, [lightboxImage]);

  const combinedStyles: React.CSSProperties = {
    ...(withLightbox && { cursor: 'pointer' }),
    ...(border && { border }),
    ...(typeof style === 'string' ? parseStyleString(style) : style),
  };

  const lightboxOverlayStyles: React.CSSProperties | undefined =
    typeof lightboxStyle === 'string' ? parseStyleString(lightboxStyle) : lightboxStyle;

  return (
    <>
      {lightboxImage ? (
        <LightboxContainer
          ref={lightboxContainerRef}
          onClick={handleCloseLightbox}
          onKeyDown={handleLightboxKeyDown}
          tabIndex={0}
        >
          <Overlay style={lightboxOverlayStyles} />
          <Image src={lightboxImage} alt={alt} />
        </LightboxContainer>
      ) : null}
      {src ? (
        <img
          src={src}
          alt={alt}
          className={className}
          width={width}
          height={height}
          style={combinedStyles}
          onClick={() => handleImageClick(src)}
        />
      ) : (
        Array.from(parsedSourceSetMap).map(([key, value]) => (
          <ColorModeAwareImage
            key={key}
            colorMode={key}
            src={value}
            alt={alt}
            className={className}
            width={width}
            height={height}
            $withLightbox={withLightbox}
            style={combinedStyles}
            onClick={() => handleImageClick(value)}
          />
        ))
      )}
    </>
  );
}

const ColorModeAwareImage = styled.img<{ colorMode: string; $withLightbox?: boolean }>`
  html:not(.${(props) => props.colorMode}) && {
    display: none;
  }
  ${({ $withLightbox }) =>
    $withLightbox &&
    `
    cursor: pointer;
  `}
`;

const Overlay = styled.div`
  background-color: var(--bg-color-modal-overlay);
  grid-column: 1 / 2;
  grid-row: 1 / 2;
  height: 100%;
  width: 100%;
  z-index: -1;
`;

const LightboxContainer = styled.div`
  display: grid;
  height: 100vh;
  left: 0;
  position: fixed;
  top: 0;
  width: 100vw;
  z-index: var(--z-index-overlay);

  &:focus {
    outline: none;
  }

  img {
    cursor: pointer;
    grid-column: 1 / 2;
    grid-row: 1 / 2;
    margin: auto;
    max-width: 90%;
    max-height: 90%;
  }
`;
