import { flatNestedArray } from '../../../utils/array';
import { min as d3Min, max as d3Max, extent as d3Extent, scaleLinear } from '../../../polyfill/d3';
/** The YAxisInputProcessor class generates Y-axis options for a line chart based on input data and previous layout results. */
export class YAxisInputProcessor {
  /**
   * This function generates the Y-axis options for a line chart based on the input data and previous layout results.
   *
   * @param {ChartOptions<LineChartDataType>} input - An object containing the chart options and data for a line chart. It includes the
   * dataSource and yAxis properties.
   * @param {LayoutProcessResultType} [previousOutput] - The output of the previous layout process,
   * which is an object containing the innerWidth and innerHeight of the chart. This parameter is
   * optional and can be undefined if it's the first layout process.
   * @returns {ChartExtend<AxisScale<AxisDomain>>} an object of type `ChartExtend<AxisScale<AxisDomain>>`, which is the result of calling the
   * `getAxisOptions` method of the `axisGenerator` object. This object contains options for the Y-axis
   * of a line chart, including the scale used for the axis.
   */
  process(input, previousOutput) {
    const { dataSource, yAxis } = input;
    const { innerWidth, innerHeight } = previousOutput;
    const { scale, ticks } = this.getScale(dataSource, [innerHeight, 0], 4);
    return {
      start: { x: 0, y: 0 },
      end: { x: 0, y: innerHeight },
      tickSize: ticks,
      scale: scale,
      labelFormatter: yAxis === null || yAxis === void 0 ? void 0 : yAxis.labelFormatter,
      width: innerWidth,
      height: innerHeight,
    };
  }
  /**
   * get y scale
   *
   * @param {ChartDataSourceItem[]} data data source
   * @param {number[]} range svg scale range
   * @param {number} ticks the y-axis ticks
   * @returns {ScaleType}y scale
   */
  getScale(data, range, ticks) {
    var _a, _b;
    const flatData = flatNestedArray(data);
    const yData = flatData.map((item) => item.y).concat(0);
    let maxYData = (_a = d3Max(yData)) !== null && _a !== void 0 ? _a : 0;
    let minYData = (_b = d3Min(yData)) !== null && _b !== void 0 ? _b : 0;
    let yScale = scaleLinear().domain([minYData, maxYData]);
    const ticksValue = (yScale.ticks ? yScale.ticks(ticks) : []);
    const step = Math.abs(ticksValue[ticksValue.length - 1] - ticksValue[ticksValue.length - 2]);
    const ext = d3Extent(ticksValue);
    const [minTickValue, maxTickValue] = ext[0] !== undefined ? ext : [0, 0];
    if (minYData < minTickValue) {
      minYData = minTickValue - step;
      ticks += 1;
    }
    if (maxYData > maxTickValue) {
      maxYData = maxTickValue + step;
      ticks += 1;
    }
    yScale = scaleLinear().domain([minYData, maxYData]).range(range);
    return { scale: yScale, ticks };
  }
}
