package com.airbnb.lottie.parser;

import android.graphics.Color;

import androidx.annotation.IntRange;

import com.airbnb.lottie.model.content.GradientColor;
import com.airbnb.lottie.parser.moshi.JsonReader;
import com.airbnb.lottie.utils.MiscUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class GradientColorParser implements com.airbnb.lottie.parser.ValueParser<GradientColor> {
  /**
   * The number of colors if it exists in the json or -1 if it doesn't (legacy bodymovin)
   */
  private int colorPoints;

  public GradientColorParser(int colorPoints) {
    this.colorPoints = colorPoints;
  }

  /**
   * Both the color stops and opacity stops are in the same array.
   * There are {@link #colorPoints} colors sequentially as:
   * [
   * ...,
   * position,
   * red,
   * green,
   * blue,
   * ...
   * ]
   * <p>
   * The remainder of the array is the opacity stops sequentially as:
   * [
   * ...,
   * position,
   * opacity,
   * ...
   * ]
   */
  @Override
  public GradientColor parse(JsonReader reader, float scale)
      throws IOException {
    List<Float> array = new ArrayList<>();
    // The array was started by Keyframe because it thought that this may be an array of keyframes
    // but peek returned a number so it considered it a static array of numbers.
    boolean isArray = reader.peek() == JsonReader.Token.BEGIN_ARRAY;
    if (isArray) {
      reader.beginArray();
    }
    while (reader.hasNext()) {
      array.add((float) reader.nextDouble());
    }
    if (isArray) {
      reader.endArray();
    }
    if (colorPoints == -1) {
      colorPoints = array.size() / 4;
    }

    float[] positions = new float[colorPoints];
    int[] colors = new int[colorPoints];

    int r = 0;
    int g = 0;
    for (int i = 0; i < colorPoints * 4; i++) {
      int colorIndex = i / 4;
      double value = array.get(i);
      switch (i % 4) {
        case 0:
          // Positions should monotonically increase. If they don't, it can cause rendering problems on some phones.
          // https://github.com/airbnb/lottie-android/issues/1675
          if (colorIndex > 0 && positions[colorIndex - 1] >= (float) value) {
            positions[colorIndex] = (float) value + 0.01f;
          } else {
            positions[colorIndex] = (float) value;
          }
          break;
        case 1:
          r = (int) (value * 255);
          break;
        case 2:
          g = (int) (value * 255);
          break;
        case 3:
          int b = (int) (value * 255);
          colors[colorIndex] = Color.argb(255, r, g, b);
          break;
      }
    }

    GradientColor gradientColor = new GradientColor(positions, colors);
    addOpacityStopsToGradientIfNeeded(gradientColor, array);
    return gradientColor;
  }

  /**
   * This cheats a little bit.
   * Opacity stops can be at arbitrary intervals independent of color stops.
   * This uses the existing color stops and modifies the opacity at each existing color stop
   * based on what the opacity would be.
   * <p>
   * This should be a good approximation is nearly all cases. However, if there are many more
   * opacity stops than color stops, information will be lost.
   */
  private void addOpacityStopsToGradientIfNeeded(GradientColor gradientColor, List<Float> array) {
    int startIndex = colorPoints * 4;
    if (array.size() <= startIndex) {
      return;
    }

    int opacityStops = (array.size() - startIndex) / 2;
    double[] positions = new double[opacityStops];
    double[] opacities = new double[opacityStops];

    for (int i = startIndex, j = 0; i < array.size(); i++) {
      if (i % 2 == 0) {
        positions[j] = array.get(i);
      } else {
        opacities[j] = array.get(i);
        j++;
      }
    }

    for (int i = 0; i < gradientColor.getSize(); i++) {
      int color = gradientColor.getColors()[i];
      color = Color.argb(
          getOpacityAtPosition(gradientColor.getPositions()[i], positions, opacities),
          Color.red(color),
          Color.green(color),
          Color.blue(color)
      );
      gradientColor.getColors()[i] = color;
    }
  }

  @IntRange(from = 0, to = 255)
  private int getOpacityAtPosition(double position, double[] positions, double[] opacities) {
    for (int i = 1; i < positions.length; i++) {
      double lastPosition = positions[i - 1];
      double thisPosition = positions[i];
      if (positions[i] >= position) {
        double progress = MiscUtils.clamp((position - lastPosition) / (thisPosition - lastPosition), 0, 1);
        return (int) (255 * MiscUtils.lerp(opacities[i - 1], opacities[i], progress));
      }
    }
    return (int) (255 * opacities[opacities.length - 1]);
  }
}