import { Helpers, LabelHelpers, Data, Domain, Scale } from "victory-core";

export const getSymbol = (data, props) => {
  if (props.bubbleProperty) {
    return "circle";
  }
  return data.symbol || props.symbol;
};

export const getBubbleSize = (datum, props) => {
  const { data, z, maxBubbleSize, minBubbleSize } = props;
  const zData = data.map((point) => point[z]);
  const zMin = Math.min(...zData);
  const zMax = Math.max(...zData);
  const getMaxRadius = () => {
    const minPadding = Math.min(
      ...Object.values(Helpers.getPadding(props.padding)),
    );
    return Math.max(minPadding, 5); // eslint-disable-line no-magic-numbers
  };
  const maxRadius = maxBubbleSize || getMaxRadius();
  const minRadius = minBubbleSize || maxRadius * 0.1; // eslint-disable-line no-magic-numbers
  if (zMax === zMin) {
    return Math.max(minRadius, 1);
  }
  const maxArea = Math.PI * Math.pow(maxRadius, 2);
  const minArea = Math.PI * Math.pow(minRadius, 2);
  const pointArea = ((datum[z] - zMin) / (zMax - zMin)) * maxArea;
  const area = Math.max(pointArea, minArea);
  const radius = Math.sqrt(area / Math.PI);
  return Math.max(radius, 1);
};

export const getSize = (datum, props) => {
  const { size, z } = props;
  if (datum.size) {
    return typeof datum.size === "function"
      ? datum.size
      : Math.max(datum.size, 1);
  } else if (typeof props.size === "function") {
    return size;
  } else if (datum[z]) {
    return getBubbleSize(datum, props);
  }
  return Math.max(size || 0, 1);
};

const getCalculatedValues = (props) => {
  const defaultStyles = Helpers.getDefaultStyles(props, "scatter");
  const style = Helpers.getStyles(props.style, defaultStyles);
  const range = {
    x: Helpers.getRange(props, "x"),
    y: Helpers.getRange(props, "y"),
  };
  const domain = {
    x: Domain.getDomain(props, "x"),
    y: Domain.getDomain(props, "y"),
  };
  const scale = {
    x: Scale.getBaseScale(props, "x")
      .domain(domain.x)
      .range(props.horizontal ? range.y : range.x),
    y: Scale.getBaseScale(props, "y")
      .domain(domain.y)
      .range(props.horizontal ? range.x : range.y),
  };
  const origin = props.polar
    ? props.origin || Helpers.getPolarOrigin(props)
    : undefined;
  const z = props.bubbleProperty || "z";

  let data = Data.getData(props);
  data = Data.formatDataFromDomain(data, domain);

  return { domain, data, scale, style, origin, z };
};

export const getBaseProps = (initialProps, fallbackProps) => {
  const modifiedProps = Helpers.modifyProps(
    initialProps,
    fallbackProps,
    "scatter",
  );
  const props = Object.assign(
    {},
    modifiedProps,
    getCalculatedValues(modifiedProps),
  );
  const {
    data,
    domain,
    events,
    height,
    origin,
    padding,
    polar,
    scale,
    name,
    sharedEvents,
    standalone,
    style,
    theme,
    width,
    labels,
    horizontal,
    disableInlineStyles,
  } = props;
  const initialChildProps = {
    parent: {
      style: style.parent,
      scale,
      domain,
      data,
      height,
      width,
      standalone,
      theme,
      origin,
      polar,
      padding,
      name,
      horizontal,
    },
  };

  return data.reduce((childProps, datum, index) => {
    const eventKey = !Helpers.isNil(datum.eventKey) ? datum.eventKey : index;
    const { x, y } = Helpers.scalePoint(props, datum);
    const dataProps = {
      x,
      y,
      datum,
      data,
      index,
      scale,
      polar,
      origin,
      horizontal,
      size: getSize(datum, props),
      symbol: getSymbol(datum, props),
      style: disableInlineStyles ? {} : style.data,
      disableInlineStyles,
    };

    childProps[eventKey] = { data: dataProps };
    const text = LabelHelpers.getText(props, datum, index);
    if (
      (text !== undefined && text !== null) ||
      (labels && (events || sharedEvents))
    ) {
      childProps[eventKey].labels = LabelHelpers.getProps(props, index);
    }

    return childProps;
  }, initialChildProps);
};
