package org.thoughtcrime.securesms.components;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.thoughtcrime.securesms.R;
import org.signal.core.util.Util;

public class ArcProgressBar extends View {

  private static final int     DEFAULT_WIDTH            = 10;
  private static final float   DEFAULT_PROGRESS         = 0f;
  private static final int     DEFAULT_BACKGROUND_COLOR = 0xFF000000;
  private static final int     DEFAULT_FOREGROUND_COLOR = 0xFFFFFFFF;
  private static final float   DEFAULT_START_ANGLE      = 0f;
  private static final float   DEFAULT_SWEEP_ANGLE      = 360f;
  private static final boolean DEFAULT_ROUNDED_ENDS     = true;

  private static final String SUPER    = "arcprogressbar.super";
  private static final String PROGRESS = "arcprogressbar.progress";

  private       float progress;
  private final float width;
  private final RectF arcRect = new RectF();

  private final Paint arcBackgroundPaint;
  private final Paint arcForegroundPaint;
  private final float arcStartAngle;
  private final float arcSweepAngle;

  public ArcProgressBar(@NonNull Context context) {
    this(context, null);
  }

  public ArcProgressBar(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public ArcProgressBar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcProgressBar, defStyleAttr, 0);

    width              = attributes.getDimensionPixelSize(R.styleable.ArcProgressBar_arcWidth, DEFAULT_WIDTH);
    progress           = attributes.getFloat(R.styleable.ArcProgressBar_arcProgress, DEFAULT_PROGRESS);
    arcBackgroundPaint = createPaint(width, attributes.getColor(R.styleable.ArcProgressBar_arcBackgroundColor, DEFAULT_BACKGROUND_COLOR));
    arcForegroundPaint = createPaint(width, attributes.getColor(R.styleable.ArcProgressBar_arcForegroundColor, DEFAULT_FOREGROUND_COLOR));
    arcStartAngle      = attributes.getFloat(R.styleable.ArcProgressBar_arcStartAngle, DEFAULT_START_ANGLE);
    arcSweepAngle      = attributes.getFloat(R.styleable.ArcProgressBar_arcSweepAngle, DEFAULT_SWEEP_ANGLE);

    if (attributes.getBoolean(R.styleable.ArcProgressBar_arcRoundedEnds, DEFAULT_ROUNDED_ENDS)) {
      arcForegroundPaint.setStrokeCap(Paint.Cap.ROUND);

      if (arcSweepAngle <= 360f) {
        arcBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
      }
    }

    attributes.recycle();
  }

  private static Paint createPaint(float width, @ColorInt int color) {
    Paint paint = new Paint();

    paint.setStrokeWidth(width);
    paint.setStyle(Paint.Style.STROKE);
    paint.setAntiAlias(true);
    paint.setColor(color);

    return paint;
  }

  public void setProgress(float progress) {
    if (this.progress != progress) {
      this.progress = progress;
      invalidate();
    }
  }

  @Override
  protected @Nullable Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();

    Bundle bundle = new Bundle();
    bundle.putParcelable(SUPER, superState);
    bundle.putFloat(PROGRESS, progress);

    return bundle;
  }

  @Override
  protected void onRestoreInstanceState(Parcelable state) {
    if (state.getClass() != Bundle.class) throw new IllegalStateException("Expected");

    Bundle restoreState = (Bundle) state;

    Parcelable superState = restoreState.getParcelable(SUPER);
    super.onRestoreInstanceState(superState);

    progress = restoreState.getLong(PROGRESS);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    float halfWidth = width / 2f;
    arcRect.set(0           + halfWidth,
                0           + halfWidth,
                getWidth()  - halfWidth,
                getHeight() - halfWidth);

    canvas.drawArc(arcRect, arcStartAngle, arcSweepAngle, false, arcBackgroundPaint);
    canvas.drawArc(arcRect, arcStartAngle, arcSweepAngle * Util.clamp(progress, 0f, 1f), false, arcForegroundPaint);
  }
}
