import React, { useEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { PipelineConnectors } from './PipelineConnectors';

const propTypes = {
  children: PropTypes.node.isRequired,
  defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
  className: PropTypes.string,
  showConnectors: PropTypes.bool,
};

const defaultProps = {
  defaultClassName: 'sui-prj-pipeline',
  className: '',
  showConnectors: false,
};

export const Pipeline = ({
  children,
  defaultClassName,
  className,
  showConnectors,
  ...attributes
}) => {
  const pipelineId = useMemo(() => Math.random().toString(36).substr(2, 9), []);
  const classes = useMemo(() => classnames(
    defaultClassName,
    className
  ), [defaultClassName, className]);
  const [connectorsKey, setConnectorsKey] = useState(0);

  // Refresh Connectors when pipeline content change
  useEffect(() => {
    if (!showConnectors) {
      return () => {};
    }

    const debounceTime = 50;

    const updateConnectors = () => {
      setConnectorsKey((k) => k + 1);
    };

    let debounce = setTimeout(updateConnectors, debounceTime);

    const observer = new MutationObserver(() => {
      clearTimeout(debounce);
      debounce = setTimeout(updateConnectors, debounceTime);
    });

    const pipelineNode = document.getElementById(pipelineId);
    const pipelineItems = pipelineNode.querySelector('.sui-prj-pipeline__items');
    observer.observe(pipelineItems, {
      subtree: true,
      childList: true,
      characterData: true,
    });

    return () => {
      observer.disconnect();
      clearTimeout(debounce);
    };
  }, [pipelineId, showConnectors]);

  return (
    <div className={classes} {...attributes} id={pipelineId}>
      <div className="sui-prj-pipeline__items">
        {children}
      </div>
      {showConnectors && (
        <PipelineConnectors key={connectorsKey} containerId={pipelineId} />
      )}
    </div>
  );
};

Pipeline.propTypes = propTypes;
Pipeline.defaultProps = defaultProps;
