package org.ntlab.acanthus_client.views.paint;

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

import org.ntlab.acanthus_client.entities.Position;
import org.ntlab.acanthus_client.entities.Stroke;
import org.ntlab.acanthus_client.views.paint.page.Point;

import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

//-----------------------------------------------------------------
// 描画キャンバスの本体
public class PaintCanvas extends View implements Runnable {

    private Path path;
    private Path path2;
    private Paint paint;
    private Paint paint2;
    private PaintViewModel paintViewModel;
    private ScheduledThreadPoolExecutor thread = new ScheduledThreadPoolExecutor(1);
    private int localstrokeNo = 0;
    private Canvas curCanvas;
    private Bitmap image;

    //-----------------------------------------------------------------
    //-----------------------------------------------------------------
    public PaintCanvas(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        path = new Path(); // 図形描画
        path2 = new Path(); // 図形描画
        paint = new Paint();//筆の種類
        paint2 = new Paint();//筆の種類
        paint.setColor(Color.BLACK);//色の指定
        paint.setStyle(Paint.Style.STROKE);//線をひく
        paint.setStrokeWidth(20);//幅
        paint2.setColor(Color.RED);//色の指定
        paint2.setStyle(Paint.Style.STROKE);//線をひく
        paint2.setStrokeWidth(20);//幅
        image = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
        curCanvas = new Canvas(image);

        thread.scheduleWithFixedDelay(this, 1000L, 2000L, TimeUnit.MILLISECONDS);

        invalidate();
    }

    //-----------------------------------------------------------------
    // getter
    public Canvas getCurCanvas() {
        return curCanvas;
    }

    //-----------------------------------------------------------------
    // setter
    public void setPaintViewModel(PaintViewModel paintViewModel) {
        this.paintViewModel = paintViewModel;
    }

    //-----------------------------------------------------------------
    //-----------------------------------------------------------------
    //
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //canvas.setBitmap(image);

        curCanvas = canvas;

        canvas.drawPath(path, paint);
        canvas.drawPath(path2, paint2);
    }

    //-----------------------------------------------------------------
    // 描画操作 (条件分岐：押したとき、動かしたとき、放した時）
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //(3-1)座標を取得（x座標、y座標）
        float x = event.getX();
        float y = event.getY();

        //(3-2)タッチの処理
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d("motion", "+++++++++++++++++++++++++++++++++++++++down======================================================");
                onTouched(x, y);
                paintViewModel.setmStrokeNo();
                paintViewModel.addLocalStrokeRequest(x, y);
                //paintViewModel.addPositionLocal(x, y);
                break;

            case MotionEvent.ACTION_MOVE:
                Log.d("motion", "move");
                onTouchedMove(x, y);
                paintViewModel.addPositionRequest(x, y);
                curCanvas.drawBitmap(image,x,y,paint);
                break;

            case MotionEvent.ACTION_UP:
                Log.d("motion", "=====================================up======================================================");
                paintViewModel.addPositionRequestFirst();
                break;
        }


        return true;
    }

    //-----------------------------------------------------------------
    // 描画クリア
    public void clearCanvas() {
        paintViewModel.deleteStrokesRequest();
        path.reset();
        path2.reset();
        invalidate();
    }

    //-----------------------------------------------------------------
    // 押した瞬間の処理
    private void onTouched(float x, float y) {
        //path = new Path();
        path.moveTo(x, y);
        invalidate();
    }

    //-----------------------------------------------------------------
    // 押した後動かした時の処理
    private void onTouchedMove(float x, float y) {
        path.lineTo(x, y);
        invalidate();
    }

    //-----------------------------------------------------------------
    //-----------------------------------------------------------------
    // 押した瞬間の処理
    private void onTouched2(float x, float y) {
        //path2 = new Path();
        path2.moveTo(x, y);
        invalidate();
    }

    //-----------------------------------------------------------------
    // 押した後動かした時の処理
    private void onTouchedMove2(float x, float y) {
        path2.lineTo(x, y);
        invalidate();
    }

    //描写するための取得
    public void getCanvas() {
        int cnt = 0;
        path2.reset();
        invalidate();
        for (Stroke s : paintViewModel.getStroke().getValue()) {
            for (Position p : s.getPositions()) {
                if (cnt == 0) {
                    onTouched2(p.getX(), p.getY());
                } else {
                    if (p.getX() == -1) {

                    } else {
                        onTouchedMove2(p.getX(), p.getY());
                    }
                }
                cnt++;
            }
            cnt = 0;
        }
        paintViewModel.deleteStroke();
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void canvassc() {
        image = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
        curCanvas = new Canvas(image);
        draw(curCanvas);


        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] byteArray = stream.toByteArray();
        byte[] encode = Base64.getEncoder().encode(byteArray);
        Log.d("motion", "=====================================up======================================================");
        Log.d("motion", "=====================================up======================================================");
        Log.d("byteArray", byteArray.toString());
        Log.d("byteImage", encode.toString());

        System.out.println("size:" + encode.length);

        for (int i = 0; i < encode.length; i++) {
            Byte b = encode[i];
            System.out.println("b[" + i + "]" + b.toString());
        }

        image.recycle();

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh){
        super.onSizeChanged(w, h, oldw, oldh);
        image = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        curCanvas = new Canvas(image);
        curCanvas.drawColor(0xFFFFFFFF);
    }

    // 一定間隔でサーバー上の筆跡を取得する（GET）
    @Override
    public void run() {
        getCanvas();
    }

    private void drawCanvas(Canvas canvas, List<Point> pts){
        if (pts.size() > 1){
            Path path = new Path();
            final int SMOOTH_VAL = 6;
            for(int i = pts.size() - 2; i < pts.size(); i++){
                if(i >= 0){
                    Point point = pts.get(i);

                    if(i == 0){
                        Point next = pts.get(i + 1);
                        point.setDx(((next.getX() - point.getX()) / SMOOTH_VAL));
                        point.setDy(((next.getY() - point.getY()) / SMOOTH_VAL));
                    }
                    else if(i == pts.size() - 1){
                        Point prev = pts.get(i - 1);
                        point.setDx(((point.getX() - prev.getX()) / SMOOTH_VAL));
                        point.setDy(((point.getY() - prev.getY()) / SMOOTH_VAL));
                    }
                    else{
                        Point next = pts.get(i + 1);
                        Point prev = pts.get(i - 1);
                        point.setDx( ((next.getX() - prev.getX()) / SMOOTH_VAL));
                        point.setDy( ((next.getY() - prev.getY()) / SMOOTH_VAL));
                    }
                }
            }

            boolean first = true;
            for(int i = 0; i < pts.size(); i++){
                Point point = pts.get(i);
                if(first){
                    first = false;
                    path.moveTo(point.getX(), point.getX());
                }
                else{
                    Point prev = pts.get(i - 1);
                    path.cubicTo(prev.getX() + prev.getDx(), prev.getY() + prev.getDy(), point.getX() - point.getDx(), point.getY() - point.getDy(), point.getX(), point.getY());
                }
            }
            canvas.drawPath(path, paint);
        } else {
            if (pts.size() == 1) {
                Point point = pts.get(0);
                canvas.drawCircle(point.getX(), point.getY(), 2, paint);
            }
        }
    }
}