package com.ruby;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

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

import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.logging.FLog;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.ViewManager;
import com.ruby.shape.OvalShape;
import com.ruby.shape.Picture;
import com.ruby.shape.RectShape;
import com.ruby.shape.Shape;

import java.util.Stack;

public class NativeCanvas extends View {
    private static final String TAG = "[NGOCDH]-" + NativeCanvas.class.getSimpleName();
    private final Stack<Shape> shapeStack;
    private Paint paint;

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

    public NativeCanvas(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public NativeCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, -1);
    }

    public NativeCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        shapeStack = new Stack<>();
        paint = new Paint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.d(TAG, "onDraw: ");
        for (Shape shape : shapeStack) {
            shape.draw(canvas);
        }
    }

    private void addShape(Shape shape) {
        shapeStack.add(shape);
        Log.d(TAG, "addShape: shapeStack size = " + shapeStack.size());
    }

    public void updatePaint(ReadableMap props) {
        if (props.hasKey("color")) {
            String color = props.getString("color");
            paint.setColor(Color.parseColor(color));
        }

        if (props.hasKey("style")) {
            String style = props.getString("style");
            if ("stroke".equals(style)) {
                paint.setStyle(Paint.Style.STROKE);
            } else if ("fill".equals(style)) {
                paint.setStyle(Paint.Style.FILL);
            } else if ("stroke_&_fill".equals(style)) {
                paint.setStyle(Paint.Style.FILL_AND_STROKE);
            }
        }

        if (props.hasKey("strokeWidth")) {
            double strokeWidth = props.getDouble("strokeWidth");
            paint.setStrokeWidth(((float) strokeWidth));
        }
    }

    public void setShapes(ReadableArray prop) {
        shapeStack.clear();
        for (int i = 0; i < prop.size(); i++) {
            ReadableMap map = prop.getMap(i);
            String type = map.getString("type");
            ReadableMap paintMap = map.getMap("paint");
            if (paintMap != null) {
                updatePaint(paintMap);
            }
            Shape shape = null;
            if ("rect".equals(type)) {
                shape = new RectShape(map);
            } else if ("oval".equals(type)) {
                shape = new OvalShape(map);
            } else if ("image".equals(type)) {
                shape = new Picture(getContext(), map, new Picture.Callback() {
                    @Override
                    public void onLoadBitmapSuccess(Bitmap bitmap) {
                        invalidate();
                    }

                    @Override
                    public void onLoadBitmapFailure(Throwable t) {
                        invalidate();
                    }
                });
            }

            if (shape != null) {
                shape.setPaint(new Paint(paint));
                addShape(shape);
            }
            paint.reset();
        }
        invalidate();
    }
}
