import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import SVG from 'svg.js';
import extendSVGPath from './utils/extendSVGPath';

if (SVG && SVG.extend) {
  extendSVGPath();
}

const propTypes = {
  containerId: PropTypes.string.isRequired,
};

const getOffset = (el, offset = { top: 0, left: 0 }) => {
  if (!el) {
    return offset;
  }

  const newOffset = {
    top: offset.top + el.offsetTop,
    left: offset.left + el.offsetLeft,
  };

  return getOffset(el.offsetParent, newOffset);
};

const getPosition = (container, fromElement, toElement) => {
  if (!container || !fromElement || !toElement) {
    return {
      start: { x: 0, y: 0 },
      end: { x: 0, y: 0 },
    };
  }

  const containerPosition = getOffset(container);
  const fromPosition = getOffset(fromElement);
  const toPosition = getOffset(toElement);

  return {
    start: {
      x: fromPosition.left - containerPosition.left + fromElement.offsetWidth,
      y: fromPosition.top - containerPosition.top + (fromElement.offsetHeight / 2),
    },
    end: {
      x: toPosition.left - containerPosition.left,
      y: toPosition.top - containerPosition.top + 12,
    },
  };
};

const getCurv = (start, end) => {
  const xRatio = (end.x - start.x) * 0.5;
  const yRatio = (end.y - start.y) * 0.2;

  return {
    start: {
      x: start.x + xRatio,
      y: start.y - yRatio,
    },
    end: {
      x: end.x - xRatio,
      y: end.y + yRatio,
    },
  };
};

const getLineClassName = (toElement) => {
  if (!toElement) {
    return '';
  }

  const allStatus = [
    'awaiting',
    'requested',
    'queued',
    'running',
    'succeeded',
    'stopping',
    'stopped',
    'failed',
    'skipped',
    'out_of_memory',
  ];

  return allStatus.reduce((classNames, status) => {
    if (!toElement) {
      return classNames;
    }

    const hasStatus = toElement.classList.contains(`as--${status}`);

    if (!hasStatus) {
      return classNames;
    }

    return `${classNames} as--${status}`;
  }, '');
};

const drawLine = (draw, container, fromElement, toElement) => {
  if (!fromElement || !toElement) {
    return;
  }

  const { start, end } = getPosition(container, fromElement, toElement);
  const curv = getCurv(start, end);

  if (!draw.path || !draw.path().M || !draw.path().C || !draw.path().addClass) {
    return;
  }

  draw
    .path()
    .M(start)
    .C(curv.start, curv.end, end)
    .addClass(`sui-prj-pipeline-connectors__line ${getLineClassName(toElement)}`);
};

const connectElements = (draw, container, elementSelector) => {
  if (!draw || !container) {
    return;
  }

  const jobs = container.querySelectorAll(elementSelector);

  jobs.forEach((job, index) => {
    if (index <= 0 || index >= jobs.length) {
      return;
    }

    drawLine(draw, container, jobs[index - 1], job);
  });
};

const destroy = (draw, svgContainer) => {
  if (draw) {
    draw.clear();
  }

  const mainSvg = svgContainer ? svgContainer.querySelector('svg') : false;

  if (mainSvg) {
    svgContainer.removeChild(mainSvg);
  }
};

export const PipelineConnectors = ({ containerId }) => {
  const svgContainerId = `${containerId}-connectors`;

  useEffect(() => {
    const draw = SVG(svgContainerId).size('100%', '100%');
    const svgContainer = document.getElementById(svgContainerId);
    const container = document.getElementById(containerId);

    connectElements(draw, container, '.sui-prj-pipeline-job');

    return () => {
      destroy(draw, svgContainer);
    };
  }, [containerId]);

  return (
    <div
      className="sui-prj-pipeline__connectors"
      id={svgContainerId}
    />
  );
};

PipelineConnectors.propTypes = propTypes;
