import React, { memo, useEffect, useMemo, useRef, useState } from "react";
import { SpeakerSummaryController } from "../../spheres";
import { useSphereState } from "../provider";
import { SpeakerSummaryItem } from "../speakerSummaryItem";
import { SummaryErrorText } from "../summaryErrorText";
import { SpeakerSummaryListContainer } from "./styled";

export interface SpeakerSummaryListProps {
  speakerSummaryController: SpeakerSummaryController;
  short?: boolean;
  style?: React.CSSProperties;
  className?: string;
  isFail?: boolean;
  errorText?: string;
  maxShowCount?: number;
}

export const SpeakerSummaryList: React.FC<SpeakerSummaryListProps> = memo(props => {
  const {
    speakerSummaryController,
    short = false,
    style,
    className,
    isFail,
    errorText,
    maxShowCount = 1,
  } = props;

  const containerRef = useRef<HTMLDivElement>(null);
  const [warpHeight, setWarpHeight] = useState(0);
  const firstItemHeightRef = useRef(0);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const displaySummaries = useSphereState(speakerSummaryController, "displaySummaries") || [];
  const summaries = useMemo(() => {
    return displaySummaries;
  }, [displaySummaries]);

  useEffect(() => {
    if (!containerRef.current) return;

    const observer = new ResizeObserver(() => {
      if (containerRef.current) {
        const { height } = containerRef.current.getBoundingClientRect();
        if (height > 0) {
          containerRef.current.style.transition = "height 0.3s";
        }

        const { sumHeight, firstItemHeight } = computeHeight(containerRef.current.childNodes);
        setWarpHeight(sumHeight);
        firstItemHeightRef.current = firstItemHeight;
      }
    });
    observer.observe(containerRef.current);

    return () => {
      observer.disconnect();
    };
  }, [summaries]);
  const contentClassRef = useRef("opacity");
  const renderedContent = useMemo(() => {
    if (errorText) {
      return <SummaryErrorText text={errorText} />;
    }

    if (isFail) {
      return <SummaryErrorText isFail />;
    }

    if (summaries.length === 0) {
      return <SummaryErrorText isEmpty />;
    }

    return (
      <SpeakerSummaryListContainer
        ref={containerRef}
        style={
          warpHeight
            ? {
                height: short ? firstItemHeightRef.current : warpHeight,
              }
            : {}
        }
      >
        {summaries.map((summary, index) => (
          <SpeakerSummaryItem
            speakerSummaryController={speakerSummaryController}
            summary={summary}
            expanded={!short}
            isExpandItem={index === maxShowCount && short}
            contentClassRef={contentClassRef}
          />
        ))}
      </SpeakerSummaryListContainer>
    );
  }, [errorText, isFail, short, summaries, speakerSummaryController, warpHeight, maxShowCount]);

  return (
    <div style={style} className={className}>
      {renderedContent}
    </div>
  );
});

const computeHeight = (nodes: NodeList, maxShowCount = 1) => {
  let firstItemHeight = 0;
  let sumHeight = 0;

  Array.prototype.forEach.call(nodes, (node: HTMLDivElement, index) => {
    const { height } = node.getBoundingClientRect();

    if (
      Array(maxShowCount + 1)
        .fill(1)
        .map((_, i) => i)
        .includes(index)
    )
      firstItemHeight += height;
    sumHeight += height + 8;

    if (index === nodes.length - 1) {
      sumHeight -= 8;
    }
  });

  return {
    firstItemHeight,
    sumHeight,
  };
};
