package wangdaye.com.geometricweather.ui.widget.weatherView.materialWeatherView.implementor;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.Size;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;

import java.util.Random;

import wangdaye.com.geometricweather.R;
import wangdaye.com.geometricweather.ui.widget.weatherView.materialWeatherView.MaterialWeatherView;

/**
 * Snow implementor.
 * */

public class SnowImplementor extends MaterialWeatherView.WeatherAnimationImplementor {

    private Paint paint;
    private Snow[] snows;

    private float lastDisplayRate;

    private float lastRotation3D;
    private static final float INITIAL_ROTATION_3D = 1000;

    @ColorInt
    private int backgroundColor;

    public static final int TYPE_SNOW_DAY = 1;
    public static final int TYPE_SNOW_NIGHT = 2;

    @IntDef({TYPE_SNOW_DAY, TYPE_SNOW_NIGHT})
    @interface TypeRule {}

    private class Snow {

        private float cX;
        private float cY;

        float centerX;
        float centerY;
        float radius;

        @ColorInt
        int color;
        float scale;

        float speedX;
        float speedY;

        private int viewWidth;
        private int viewHeight;

        private int canvasSize;

        private Snow(int viewWidth, int viewHeight, @ColorInt int color, float scale) {
            this.viewWidth = viewWidth;
            this.viewHeight = viewHeight;

            this.canvasSize = (int) Math.pow(viewWidth * viewWidth + viewHeight * viewHeight, 0.5);

            this.radius = (float) (viewWidth * 0.0213 * scale);

            this.color = color;
            this.scale = scale;

            this.speedY = viewWidth / 350f;

            this.init(true);
        }

        private void init(boolean firstTime) {
            Random r = new Random();
            cX = r.nextInt(canvasSize);
            if (firstTime) {
                cY = r.nextInt((int) (canvasSize - radius)) - canvasSize;
            } else {
                cY = -radius;
            }
            speedX = r.nextInt((int) (2 * speedY)) - speedY;

            computeCenterPosition();
        }

        private void computeCenterPosition() {
            centerX = (int) (cX - (canvasSize - viewWidth) * 0.5);
            centerY = (int) (cY - (canvasSize - viewHeight) * 0.5);
        }

        void move(long interval, float deltaRotation3D) {
            cX += speedX * interval * Math.pow(scale, 1.5);
            cY += speedY * interval * (Math.pow(scale, 1.5) - 5 * Math.sin(deltaRotation3D * Math.PI / 180.0));

            if (centerY >= canvasSize) {
                init(false);
            } else {
                computeCenterPosition();
            }
        }
    }

    public SnowImplementor(@Size(2) int[] canvasSizes, @TypeRule int type) {
        this.paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);

        int[] colors = new int[3];
        switch (type) {
            case TYPE_SNOW_DAY:
                backgroundColor = Color.rgb(104, 186, 255);
                colors = new int[] {
                        Color.rgb(128, 197, 255),
                        Color.rgb(185, 222, 255),
                        Color.rgb(255, 255, 255)};
                break;

            case TYPE_SNOW_NIGHT:
                backgroundColor = Color.rgb(26, 91, 146);
                colors = new int[] {
                        Color.rgb(40, 102, 155),
                        Color.rgb(99, 144, 182),
                        Color.rgb(255, 255, 255)};
                break;
        }
        float[] scales = new float[] {0.6F, 0.8F, 1};

        this.snows = new Snow[51];
        for (int i = 0; i < snows.length; i ++) {
            snows[i] = new Snow(
                    canvasSizes[0], canvasSizes[1],
                    colors[i * 3 / snows.length], scales[i * 3 / snows.length]);
        }

        this.lastDisplayRate = 0;
        this.lastRotation3D = INITIAL_ROTATION_3D;
    }

    @Override
    public void updateData(@Size(2) int[] canvasSizes, long interval,
                           float rotation2D, float rotation3D) {
        for (Snow s : snows) {
            s.move(interval, lastRotation3D == INITIAL_ROTATION_3D ? 0 : rotation3D - lastRotation3D);
        }
        lastRotation3D = rotation3D;
    }

    @Override
    public void draw(@Size(2) int[] canvasSizes, Canvas canvas,
                     float displayRate, float scrollRate, float rotation2D, float rotation3D) {

        if (displayRate >= 1) {
            canvas.drawColor(backgroundColor);
        } else {
            canvas.drawColor(
                    ColorUtils.setAlphaComponent(
                            backgroundColor,
                            (int) (displayRate * 255)));
        }

        if (scrollRate < 1) {
            canvas.rotate(
                    rotation2D,
                    canvasSizes[0] * 0.5F,
                    canvasSizes[1] * 0.5F);
            for (Snow s : snows) {
                paint.setColor(s.color);
                if (displayRate < lastDisplayRate) {
                    paint.setAlpha((int) (displayRate * (1 - scrollRate) * 255));
                } else {
                    paint.setAlpha((int) ((1 - scrollRate) * 255));
                }
                canvas.drawCircle(s.centerX, s.centerY, s.radius, paint);
            }
        }

        lastDisplayRate = displayRate;
    }

    @ColorInt
    public static int getThemeColor(Context context, @TypeRule int type) {
        switch (type) {
            case TYPE_SNOW_DAY:
                return Color.rgb(104, 186, 255);

            case TYPE_SNOW_NIGHT:
                return Color.rgb(26, 91, 146);
        }
        return ContextCompat.getColor(context, R.color.colorPrimary);
    }
}