import {
  JSX,
  splitProps,
  Component,
  createSignal,
  onMount,
  createRenderEffect,
  Show,
} from "solid-js";
import { css } from "solid-styled";
import { decode } from "blurhash";

type ImgProps = {
  blurhash?: string;
  keepBlur?: boolean;
} & JSX.HTMLElementTags["img"];

const Img: Component<ImgProps> = (props) => {
  let canvas: HTMLCanvasElement;
  let imgE: HTMLImageElement;
  const [managed, passthough] = splitProps(props, [
    "blurhash",
    "keepBlur",
    "class",
    "classList",
    "style",
  ]);
  const [isImgLoaded, setIsImgLoaded] = createSignal(false);
  const [imgSize, setImgSize] = createSignal<{
    width: number;
    height: number;
  }>();

  const isBlurEnabled = () => managed.keepBlur || !isImgLoaded();

  css`
    :where(.img-root) {
      display: inline-block;
      position: relative;

      > img:first-of-type {
        object-fit: contain;
        object-position: center;
        width: 100%;
        height: 100%;
        visibility: ${isBlurEnabled() ? "hidden" : "initial"};
      }
    }

    :where(.cover) {
      display: ${isBlurEnabled() ? "block" : "none"};
      position: absolute;
      left: 0;
      top: 0;
      height: ${`${imgSize()?.height ?? 0}px`};
      width: ${`${imgSize()?.width ?? 0}px`};
    }
  `;

  const onImgLoaded = () => {
    setIsImgLoaded(true);
    setImgSize({
      width: imgE!.width,
      height: imgE!.height,
    });
  };

  const onMetadataLoaded = () => {
    setImgSize({
      width: imgE!.width,
      height: imgE!.height,
    });
  };

  onMount(() => {
    setImgSize((x) => {
      const parent = imgE!.parentElement;
      if (!parent) return x;
      return x
        ? x
        : {
            width: parent.clientWidth,
            height: parent.clientHeight,
          };
    });
  });

  return (
    <div
      classList={{
        ...managed.classList,
        [managed.class ?? ""]: true,
        "img-root": true,
      }}
      style={managed.style}
    >
      <Show when={managed.blurhash}>
        <canvas
          ref={(canvas) => {
            createRenderEffect(() => {
              if (!managed.blurhash) return;
              const ctx = canvas.getContext("2d");
              if (!ctx) return;
              const size = imgSize();
              if (!size) return;
              const imgd = ctx?.createImageData(size.width, size.height);
              const pixels = decode(managed.blurhash, size.width, size.height);
              imgd.data.set(pixels);
              ctx.putImageData(imgd, 0, 0);
            });
          }}
          class="cover"
          role="presentation"
        />
      </Show>

      <img
        ref={imgE!}
        {...passthough}
        onLoad={onImgLoaded}
        onLoadedMetadata={onMetadataLoaded}
      />
    </div>
  );
};

export default Img;