package io.github.longluo.ui.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnticipateInterpolator;

import androidx.annotation.Nullable;

import io.github.longluo.ui.R;

/**
 * 播放暂停动效的按钮
 */
public final class PlayButton extends View {

    /** 播放状态 */
    public static final int STATE_PLAY = 0;
    /** 暂停状态 */
    public static final int STATE_PAUSE = 1;

    /** 当前状态 */
    private int mCurrentState = STATE_PAUSE;

    /** 动画时间 */
    private int mAnimDuration;

    private final Paint mPaint;

    private int mWidth, mHeight;

    private int mCenterX, mCenterY;

    private int mCircleRadius;

    private RectF mRectF, mBgRectF;

    private float mFraction = 1;

    private final Path mPath, mDstPath;

    private final PathMeasure mPathMeasure;

    private float mPathLength;

    public PlayButton(Context context) {
        this(context, null);
    }

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

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

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PlayButton);
        int lineColor = typedArray.getColor(R.styleable.PlayButton_pb_lineColor, Color.WHITE);
        int lineSize = typedArray.getInteger(R.styleable.PlayButton_pb_lineSize, (int) getResources().getDimension(R.dimen.dp_4));
        mAnimDuration = typedArray.getInteger(R.styleable.PlayButton_pb_animDuration, 200);
        typedArray.recycle();

        // 关闭硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setColor(lineColor);
        mPaint.setStrokeWidth(lineSize);
        mPaint.setPathEffect(new CornerPathEffect(1));

        mPath = new Path();
        mDstPath = new Path();
        mPathMeasure = new PathMeasure();
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        mWidth = width * 9 / 10;
        mHeight = height * 9 / 10;
        mCircleRadius = mWidth / (int) getResources().getDimension(R.dimen.dp_4);
        mCenterX = width / 2;
        mCenterY = height / 2;
        mRectF = new RectF(mCenterX - mCircleRadius, mCenterY + 0.6f * mCircleRadius,
                mCenterX + mCircleRadius, mCenterY + 2.6f * mCircleRadius);
        mBgRectF = new RectF(mCenterX - mWidth / 2f ,mCenterY - mHeight / 2f ,
                mCenterX + mWidth / 2f, mCenterY + mHeight / 2f);
        mPath.moveTo(mCenterX - mCircleRadius, mCenterY + 1.8f * mCircleRadius);
        mPath.lineTo(mCenterX - mCircleRadius, mCenterY - 1.8f * mCircleRadius);
        mPath.lineTo(mCenterX + mCircleRadius, mCenterY);
        mPath.close();
        mPathMeasure.setPath(mPath, false);
        mPathLength = mPathMeasure.getLength();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        switch (MeasureSpec.getMode(widthMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) getResources().getDimension(R.dimen.dp_60), MeasureSpec.EXACTLY);
                break;
            case MeasureSpec.EXACTLY:
            default:
                break;
        }

        switch (MeasureSpec.getMode(heightMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) getResources().getDimension(R.dimen.dp_60), MeasureSpec.EXACTLY);
                break;
            case MeasureSpec.EXACTLY:
            default:
                break;
        }

        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(mCenterX, mCenterY, mWidth / 2f, mPaint);
        if (mFraction < 0) {
            // 弹性部分
            canvas.drawLine(mCenterX + mCircleRadius, mCenterY - 1.6f * mCircleRadius + 10 * mCircleRadius * mFraction,
                    mCenterX + mCircleRadius, mCenterY + 1.6f * mCircleRadius + 10 * mCircleRadius * mFraction, mPaint);

            canvas.drawLine(mCenterX - mCircleRadius, mCenterY - 1.6f * mCircleRadius,
                    mCenterX - mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint);

            canvas.drawArc(mBgRectF, -105 , 360 , false, mPaint);
        } else if (mFraction <= 0.3) {
            // 右侧直线和下方曲线
            canvas.drawLine(mCenterX + mCircleRadius, mCenterY - 1.6f * mCircleRadius + mCircleRadius * 3.2f / 0.3f * mFraction,
                    mCenterX + mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint);

            canvas.drawLine(mCenterX - mCircleRadius, mCenterY - 1.6f * mCircleRadius,
                    mCenterX - mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint);

            if (mFraction != 0) {
                canvas.drawArc(mRectF, 0f, 180f / 0.3f * mFraction, false, mPaint);
            }

            canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint);
        } else if (mFraction <= 0.6) {
            // 下方曲线和三角形
            canvas.drawArc(mRectF, 180f / 0.3f * (mFraction - 0.3f), 180 - 180f / 0.3f * (mFraction - 0.3f), false , mPaint);

            mDstPath.reset();
            mPathMeasure.getSegment(0.02f * mPathLength, 0.38f * mPathLength + 0.42f * mPathLength / 0.3f * (mFraction - 0.3f) ,
                    mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);

            canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint);
        } else if (mFraction <= 0.8) {
            // 三角形
            mDstPath.reset();
            mPathMeasure.getSegment(0.02f * mPathLength + 0.2f * mPathLength / 0.2f * (mFraction - 0.6f)
                    , 0.8f * mPathLength + 0.2f * mPathLength / 0.2f * (mFraction - 0.6f) ,
                    mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);

            canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint);
        } else {
            // 弹性部分
            mDstPath.reset();
            mPathMeasure.getSegment(10 * mCircleRadius * (mFraction - 1)
                    , mPathLength ,
                    mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);
        }
    }

    /**
     * 播放状态
     */
    public void play() {
        if (mCurrentState == STATE_PLAY) {
            return;
        }
        mCurrentState = STATE_PLAY;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1f, 100f);
        valueAnimator.setDuration(mAnimDuration);
        valueAnimator.setInterpolator(new AnticipateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            mFraction = 1 - animation.getAnimatedFraction();
            invalidate();
        });
        valueAnimator.start();
    }

    /**
     * 暂停状态
     */
    public void pause() {
        if (mCurrentState == STATE_PAUSE) {
            return;
        }
        mCurrentState = STATE_PAUSE;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.f, 100f);
        valueAnimator.setDuration(mAnimDuration);
        valueAnimator.setInterpolator(new AnticipateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            mFraction = animation.getAnimatedFraction();
            invalidate();
        });
        valueAnimator.start();
    }

    /**
     * 获取当前状态
     */
    public int getCurrentState() {
        return mCurrentState;
    }

    /**
     * 设置动画时间
     */
    public void setAnimDuration(int duration) {
        mAnimDuration = duration;
    }

    /**
     * 设置线条颜色
     */
    public void setLineColor(int color) {
        mPaint.setColor(color);
        invalidate();
    }

    /**
     * 设置线条大小
     */
    public void setLineSize(int size) {
        mPaint.setStrokeWidth(size);
        invalidate();
    }
}