package com.bokecc.livemodule.view.redpacket;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture;
import android.os.SystemClock;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;

import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.bokecc.livemodule.utils.DensityUtil.dp2px;
import static com.bokecc.livemodule.view.redpacket.RedPacketRes.TYPE_BOOM;
import static com.bokecc.livemodule.view.redpacket.RedPacketRes.TYPE_GIFT;
import static com.bokecc.livemodule.view.redpacket.RedPacketRes.TYPE_PACKET;


/**
 * 红包雨渲染器
 * @author w
 */
public class RedPacketRender extends Thread implements TextureView.SurfaceTextureListener {
    private final Resources resources;
    private OnStateChangeListener mOnStateChangeListener;
    private static final String TAG = "zzw RedPacketRender";
    private final Object mLock = new Object();        // guards mSurfaceTexture, mDone
    private SurfaceTexture mSurfaceTexture;
    private volatile boolean mDone;
    private int mWidth;     // SurfaceTexture宽度
    private int mHeight;    //SurfaceTexture高度
    private int screenHeight ; //屏幕高度
    private int screenWidth ;  //屏幕宽度
    private volatile List<BoxInfo> mRedPackets = new CopyOnWriteArrayList<>();//红包容器
    private Random mRandom = new Random();
    private Paint mPaint;
    private final int SLEEP_TIME = 15; //多少毫秒一帧（请根据设备性能权衡
    private float slidingRate = 1.5f;//速率 值越大 速度越小
    private float BLOCK_SPEED = SLEEP_TIME/slidingRate; //红包每一帧的移动距离（在xxhdpi基准下采用 耗时/1.3f）
    private int rate = 2;//正常红包的取模 降低晃动频率
    private BoxInfo mLastDrawRedPacket; //最后绘制的红包--礼物的那个。
    public int showTime = 700; //动画展示的时长
    private List<BoxInfo> boxInfos ;//红包的元数据 待设置x y
    private final RedPacketRes redPacketRes; //红包的资源管理器

    public interface OnStateChangeListener {
        void onRun();

        void onEnd(boolean isCallBack);
    }

    public RedPacketRender(Resources resources, List<BoxInfo> boxInfos, Context context) {
        super("TextureViewCanvas Renderer");
        redPacketRes = new RedPacketRes();
        redPacketRes.defaultHeight = dp2px(context,84);
        redPacketRes.defaultWidth = dp2px(context,84);
        this.resources=resources;
        screenHeight = resources.getDisplayMetrics().heightPixels;
        screenWidth = resources.getDisplayMetrics().widthPixels;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 抗锯齿画笔
        this.boxInfos = boxInfos;
    }

    public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
        mOnStateChangeListener = onStateChangeListener;
    }

    @Override
    public void run() {
        if (mOnStateChangeListener != null) {
            mOnStateChangeListener.onRun();
        }
        mDone = false;
        while (!mDone) {
            synchronized (mLock) {
                while (!mDone && mSurfaceTexture == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ie) {
                        throw new RuntimeException(ie);     // not expected
                    }
                }
                if (mDone) {
                    break;
                }
            }
            doAnimation();
        }
    }
    //处理数据
    private void handleData(){
        mRedPackets.clear();
        int xLength = mWidth;//其实就是屏幕宽度
        int sp = (xLength-redPacketRes.defaultWidth*3)/6;
        int centerX = (xLength-redPacketRes.defaultWidth)/2;
        int leftX = sp;
        int rightX = (xLength-redPacketRes.defaultWidth)-sp;
        //第一个红包的位置
        int firstY = 0;
        int yLength = mHeight;
        int diff = 0;
        int maxDiff = Math.max(0,(xLength - redPacketRes.defaultWidth * 3) / 6+redPacketRes.defaultWidth*15/100);
        for (int i = 0; i < boxInfos.size(); i++) {

            BoxInfo redPacket = boxInfos.get(i);
            if (i >= 3) {
                diff = mRandom.nextInt(maxDiff * 2 + 1) - maxDiff;
            }
            switch (i % 3) {
                //右
                case 1:
                    redPacket.nextX(rightX + diff);
                    redPacket.nextY(firstY - yLength * i / 10 + diff+mRandom.nextInt(redPacketRes.defaultHeight));
                    break;
                //左
                case 2:
                    redPacket.nextX(leftX + diff);
                    redPacket.nextY(firstY - yLength * i / 10 + yLength / 9 + diff+mRandom.nextInt(redPacketRes.defaultHeight));
                    break;
                //中间
                default:
                    redPacket.nextX(centerX + diff);
                    redPacket.nextY(firstY - yLength * i / 10 + diff+mRandom.nextInt(redPacketRes.defaultHeight));
                    break;
            }
            mRedPackets.add(redPacket);
        }
        boxInfos.clear();
    }
    //绘制红包雨
    private void doAnimation() {
        // Create a Surface for the SurfaceTexture.
        Surface surface = null;
        synchronized (mLock) {
            SurfaceTexture surfaceTexture = mSurfaceTexture;
            if (surfaceTexture == null) {
                Log.d(TAG, "ST null on entry");
                return;
            }
            surface = new Surface(surfaceTexture);
        }

        long lastNano = 0;
        //整理红包雨数据
        handleData();
        drawRedPacket(surface,lastNano);

        surface.release();
        mRedPackets.clear();
        redPacketRes.clear();
    }
    //红包的真正绘制
    private void drawRedPacket(Surface surface, long lastNano) {
        while (!mDone) {
            final long startNano = System.nanoTime();
            Canvas canvas = null;
            try {
                canvas = surface.lockCanvas(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (canvas == null) {
                Log.d(TAG, "lockCanvas() failed");
                break;
            }
            try {
                // just curious
                if (canvas.getWidth() != mWidth || canvas.getHeight() != mHeight) {
                    Log.d(TAG, "WEIRD: width/height mismatch");
                }
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                boolean hasShowRedPacket = false;
                long nano = System.nanoTime();
                float dirY;
                if (lastNano == 0) {
                    dirY = BLOCK_SPEED;
                } else {
                    float dirMills = (nano - lastNano) / 1000_000F;
                    dirY = Math.round(dirMills * BLOCK_SPEED / SLEEP_TIME);
                }
                lastNano = nano;
                int typeIndex = 0;
                synchronized(this){
                    for (BoxInfo redPacket : mRedPackets) {
                        float y = redPacket.nextY(dirY);
                        float x = redPacket.nextX(0);
                        if (y >  -redPacketRes.defaultHeight && y < mHeight) {
                            typeIndex = redPacket.addIndex();
                            switch (redPacket.type) {
                                //爆炸!
                                case TYPE_BOOM:
                                    y = redPacket.nextY(-dirY);//位置复原
                                    mLastDrawRedPacket = redPacket;
                                    if ((typeIndex-redPacketRes.NO_LIST.length)*SLEEP_TIME>showTime)
                                        redPacket.nextY(screenHeight);
                                    mLastDrawRedPacket = null;
                                    break;
                                case TYPE_GIFT:
                                    y = redPacket.nextY(-dirY);//位置复原
                                    redPacket.addIndex();
                                    mLastDrawRedPacket = redPacket;
                                    // 5秒且等红包雨下完。
                                    if ((typeIndex-redPacketRes.GIFT_LIST.length)*SLEEP_TIME>showTime){
                                        redPacket.nextY(screenHeight);
                                        mLastDrawRedPacket = null;
                                    }
                                    break;
                            }
                            if (y>=(0-redPacketRes.defaultHeight)&&y<=screenHeight){
                                if (redPacket.getType() == TYPE_GIFT){
                                    Bitmap currentBitmao = redPacketRes.getCurrentBitmao(redPacket, resources, rate * 3);
                                    if (currentBitmao!=null){
                                        canvas.drawBitmap(currentBitmao,x-redPacketRes.defaultWidth*15/100, y, mPaint);
                                    }
                                }else{
                                    Bitmap currentBitmao = redPacketRes.getCurrentBitmao(redPacket, resources, rate);
                                    if (currentBitmao!=null){
                                        canvas.drawBitmap(currentBitmao,x, y, mPaint);
                                    }
                                }

                            }
                            hasShowRedPacket = true;
                        }
                        //删除已经到窗口外的红包
                        if (y>mHeight){
                            mRedPackets.remove(redPacket);
                        }
                    }
                }
                if (!hasShowRedPacket) {
                    mRedPackets.clear();
                    halt(true);
                }
            } finally {
                try {
                    surface.unlockCanvasAndPost(canvas);
                } catch (IllegalArgumentException iae) {
                    Log.d(TAG, "unlockCanvasAndPost failed: " + iae.getMessage());
                    break;
                }
            }
            long costNano = System.nanoTime() - startNano;
            long sleepMills = SLEEP_TIME - costNano / 1000_000;
            if (sleepMills > 0) {
                SystemClock.sleep(sleepMills);
            }
        }
    }

    /**
     * 红包雨点击事件，返回点击的item.
     *
     * @param x 点击的x坐标
     * @param y 点击的y坐标
     * @return 返回点中的红包position。（若未点中则返回-1）
     */
    public BoxInfo getClickPosition(int x, int y,int type) {
        if (!mDone && mRedPackets.size() > 0) {
            for (BoxInfo redPacket : mRedPackets) {
                if (redPacket.getType()==TYPE_PACKET
                        && redPacket.isInArea(x, y, redPacketRes.defaultWidth, redPacketRes.defaultHeight)) {
                    redPacket.setType(type);
                    return redPacket;
                }
            }
        }
        return null;
    }

    //Tells the thread to stop running.
    public void halt(boolean isCallBack) {
        synchronized (mLock) {
            mDone = true;
            mLock.notify();
        }
        boxInfos.clear();
        redPacketRes.clear();
        if (mOnStateChangeListener != null) {
            mOnStateChangeListener.onEnd(isCallBack);
        }
    }
    //设置红包雨的速度
    public void setSlidingRate(int rate){
        if (rate == 0){//慢
            slidingRate = 3;
            BLOCK_SPEED =  SLEEP_TIME/slidingRate;
        }else if (rate == 1){
            slidingRate = 2;
            BLOCK_SPEED =  SLEEP_TIME/slidingRate;
        }else if (rate == 2){
            slidingRate = 1;
            BLOCK_SPEED =  SLEEP_TIME/slidingRate;
        }

    }
    @Override   // will be called on UI thread
    public void onSurfaceTextureAvailable(SurfaceTexture st, int width, int height) {
        Log.d(TAG, "onSurfaceTextureAvailable(" + width + "x" + height + ")");
        mWidth = width;
        mHeight = height;
        synchronized (mLock) {
            mSurfaceTexture = st;
            mLock.notify();
        }
    }

    @Override   // will be called on UI thread
    public void onSurfaceTextureSizeChanged(SurfaceTexture st, int width, int height) {
        Log.d(TAG, "onSurfaceTextureSizeChanged(" + width + "x" + height + ")");
        mWidth = width;
        mHeight = height;
    }

    @Override   // will be called on UI thread
    public boolean onSurfaceTextureDestroyed(SurfaceTexture st) {
        Log.d(TAG, "onSurfaceTextureDestroyed");

        synchronized (mLock) {
            mSurfaceTexture = null;
        }
        return true;
    }

    @Override   // will be called on UI thread
    public void onSurfaceTextureUpdated(SurfaceTexture st) {
        //Log.d(TAG, "onSurfaceTextureUpdated");
    }
}
