package com.izouma.mobilecybergames;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

import com.alivc.live.pusher.AlivcAudioAACProfileEnum;
import com.alivc.live.pusher.AlivcFpsEnum;
import com.alivc.live.pusher.AlivcLivePushConfig;
import com.alivc.live.pusher.AlivcLivePushError;
import com.alivc.live.pusher.AlivcLivePushErrorListener;
import com.alivc.live.pusher.AlivcLivePushInfoListener;
import com.alivc.live.pusher.AlivcLivePushNetworkListener;
import com.alivc.live.pusher.AlivcLivePusher;
import com.alivc.live.pusher.AlivcPreviewOrientationEnum;
import com.alivc.live.pusher.AlivcResolutionEnum;

import java.util.regex.Pattern;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;

import static android.content.Context.WINDOW_SERVICE;

public class ScreenStreamPlugin implements MethodChannel.MethodCallHandler, PluginRegistry.ActivityResultListener {
    private static final String TAG                             = "ScreenStreamPlugin";
    private static final int    CAPTURE_PERMISSION_REQUEST_CODE = 0x1123;
    private static final int    FLOATING_WINDOW_REQUEST_CODE    = 0x1124;

    private final PluginRegistry.Registrar registrar;

    private AlivcLivePushConfig  mAlivcLivePushConfig;
    private AlivcLivePusher      mAlivcLivePusher = null;
    private boolean              started          = false;
    private String               url;
    private MethodChannel.Result result;

    private WindowManager              windowManager;
    private WindowManager.LayoutParams layoutParams;
    private Button                     floatButton;

    public static void registerWith(PluginRegistry.Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "screen_stream");
        MethodChannel.MethodCallHandler methodCallHandler = new ScreenStreamPlugin(registrar);
        registrar.addActivityResultListener((PluginRegistry.ActivityResultListener) methodCallHandler);
        channel.setMethodCallHandler(methodCallHandler);
    }

    public ScreenStreamPlugin(PluginRegistry.Registrar registrar) {
        this.registrar = registrar;
        this.registrar.context().registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if ("onResume".equals(intent.getStringExtra("event"))) {
                    if (floatButton != null) {
                        floatButton.setVisibility(View.GONE);
                    }
                } else if ("onPause".equals(intent.getStringExtra("event"))) {
                    if (floatButton != null) {
                        floatButton.setVisibility(View.VISIBLE);
                    }
                }
            }
        }, new IntentFilter(MainActivity.APP_LIFECYCLE_ACTION));
        AlivcLivePushConfig.setMediaProjectionPermissionResultData(null);
        mAlivcLivePushConfig = new AlivcLivePushConfig();//初始化推流配置类
        mAlivcLivePushConfig.setResolution(AlivcResolutionEnum.RESOLUTION_720P);//分辨率540P，最大支持720P
        mAlivcLivePushConfig.setFps(AlivcFpsEnum.FPS_10); //建议用户使用20fps
        mAlivcLivePushConfig.setEnableBitrateControl(true); // 打开码率自适应，默认为true
        mAlivcLivePushConfig.setPreviewOrientation(AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT); // 默认为竖屏，可设置home键向左或向右横屏。
        mAlivcLivePushConfig.setAudioProfile(AlivcAudioAACProfileEnum.AAC_LC);//设置音频编码模式
        mAlivcLivePushConfig.setEnableBitrateControl(true);// 打开码率自适应，默认为true

        windowManager = (WindowManager) this.registrar.context().getSystemService(WINDOW_SERVICE);
        layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.width = 200;
        layoutParams.height = 100;
        layoutParams.x = 300;
        layoutParams.y = 300;
    }

    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        this.result = result;
        if ("start".equals(methodCall.method)) {
            url = methodCall.argument("url");
            if (!TextUtils.isEmpty(url)) {
                if (Pattern.matches("^(?i)rtmp://.*", url)) {
                    if (!start()) {
                        result.error("start fail", "need android 5.0", null);
                    }
                    return;
                }
            }
            result.error("wrong url", url, null);
        } else if ("stop".equals(methodCall.method)) {
            stop();
            result.success("success");
        } else if ("checkPermission".equals(methodCall.method)) {
            if (checkPermission()) {
                result.success(true);
            } else {
                result.success(false);
            }
        } else if ("requestPermission".equals(methodCall.method)) {
            requestPermission();
        }
    }

    private boolean start() {
        if (started) {
            mAlivcLivePusher.stopPush();
            return true;
        } else {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) registrar.activeContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
                registrar.activity().startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), CAPTURE_PERMISSION_REQUEST_CODE);
                return true;
            }
        }
        return false;
    }

    private boolean checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return Settings.canDrawOverlays(registrar.context());
        }
        return true;
    }

    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(registrar.context())) {
                registrar.activity().startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + registrar.context().getPackageName())), FLOATING_WINDOW_REQUEST_CODE);
                return;
            }
        }
        result.success(true);
    }

    private void showFloatWindow() {
        if (floatButton != null) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本
            if (Settings.canDrawOverlays(registrar.context())) {
                floatButton = new Button(registrar.context().getApplicationContext());
                floatButton.setText("CLICK ME!");
                floatButton.setBackgroundColor(Color.LTGRAY);
                floatButton.setVisibility(View.GONE);
                windowManager.addView(floatButton, layoutParams);
                floatButton.setOnTouchListener(new FloatingOnTouchListener());
            }
        } else {
            floatButton = new Button(registrar.context().getApplicationContext());
            floatButton.setText("CLICK ME!");
            floatButton.setBackgroundColor(Color.LTGRAY);
            floatButton.setVisibility(View.GONE);
            windowManager.addView(floatButton, layoutParams);
            floatButton.setOnTouchListener(new FloatingOnTouchListener());
        }
    }

    private boolean stop() {
        if (mAlivcLivePusher != null && mAlivcLivePusher.isPushing()) {
            mAlivcLivePusher.stopPush();
        }
        if (floatButton != null) {
            windowManager.removeView(floatButton);
            floatButton = null;
        }
        return true;
    }

    private void startPushWithoutSurface() {
        showFloatWindow();
        mAlivcLivePusher = new AlivcLivePusher();
        try {
            mAlivcLivePusher.init(registrar.context(), mAlivcLivePushConfig);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

        mAlivcLivePusher.setLivePushInfoListener(new AlivcLivePushInfoListener() {
            @Override
            public void onPreviewStarted(AlivcLivePusher pusher) {

            }

            @Override
            public void onPreviewStoped(AlivcLivePusher pusher) {

            }

            @Override
            public void onPushStarted(AlivcLivePusher pusher) {
                Log.d(TAG, "onPushStarted");
                started = true;
                registrar.activity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(registrar.context(), "开始录屏", Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void onFirstAVFramePushed(AlivcLivePusher alivcLivePusher) {
                Log.d(TAG, "onFirstAVFramePushed");
            }

            @Override
            public void onPushPauesed(AlivcLivePusher pusher) {
                Log.d(TAG, "onPushPauesed");

            }

            @Override
            public void onPushResumed(AlivcLivePusher pusher) {
                Log.d(TAG, "onPushResumed");
            }

            @Override
            public void onPushStoped(AlivcLivePusher pusher) {
                Log.d(TAG, "onPushStopped");
                started = false;
                mAlivcLivePusher = null;
                registrar.activity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(registrar.context(), "录屏结束", Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void onPushRestarted(AlivcLivePusher pusher) {
                Log.d(TAG, "onPushRestarted");
            }

            @Override
            public void onFirstFramePreviewed(AlivcLivePusher pusher) {
                Log.d(TAG, "onFirstFramePreviewed");
            }

            @Override
            public void onDropFrame(AlivcLivePusher pusher, int countBef, int countAft) {
                Log.d(TAG, "onDropFrame");
            }

            @Override
            public void onAdjustBitRate(AlivcLivePusher pusher, int curBr, int targetBr) {
                Log.d(TAG, "onAdjustBitRate");
            }

            @Override
            public void onAdjustFps(AlivcLivePusher pusher, int curFps, int targetFps) {
                Log.d(TAG, "onAdjustFps");
            }
        });
        mAlivcLivePusher.setLivePushErrorListener(new AlivcLivePushErrorListener() {
            @Override
            public void onSystemError(AlivcLivePusher alivcLivePusher, AlivcLivePushError alivcLivePushError) {
                Log.d(TAG, "onSystemError\n" + alivcLivePushError.getMsg());
            }

            @Override
            public void onSDKError(AlivcLivePusher alivcLivePusher, AlivcLivePushError alivcLivePushError) {
                Log.d(TAG, "onSDKError\n" + alivcLivePushError.getMsg());
            }
        });
        mAlivcLivePusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() {
            @Override
            public void onNetworkPoor(AlivcLivePusher alivcLivePusher) {

            }

            @Override
            public void onNetworkRecovery(AlivcLivePusher alivcLivePusher) {

            }

            @Override
            public void onReconnectStart(AlivcLivePusher alivcLivePusher) {

            }

            @Override
            public void onReconnectFail(AlivcLivePusher alivcLivePusher) {
                Log.e(TAG, "onReconnectFail");
            }

            @Override
            public void onReconnectSucceed(AlivcLivePusher alivcLivePusher) {

            }

            @Override
            public void onSendDataTimeout(AlivcLivePusher alivcLivePusher) {

            }

            @Override
            public void onConnectFail(AlivcLivePusher alivcLivePusher) {
                Log.e(TAG, "onConnectFail");
            }

            @Override
            public String onPushURLAuthenticationOverdue(AlivcLivePusher alivcLivePusher) {
                return null;
            }

            @Override
            public void onSendMessage(AlivcLivePusher alivcLivePusher) {

            }
        });

        mAlivcLivePusher.startPreview(null);
        mAlivcLivePusher.startPush(url);
        mAlivcLivePusher.setCaptureVolume(50);
    }

    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case CAPTURE_PERMISSION_REQUEST_CODE: {
                if (resultCode == Activity.RESULT_OK) {
                    AlivcLivePushConfig.setMediaProjectionPermissionResultData(data);
                    if (mAlivcLivePushConfig.getMediaProjectionPermissionResultData() != null) {
                        if (mAlivcLivePusher == null) {
                            startPushWithoutSurface();
                            if (result != null) {
                                result.success("success");
                                return true;
                            }
                        }
                    }
                }
                if (result != null) {
                    result.error("needs permission", "permission not granted", null);
                }
            }
            break;
            case FLOATING_WINDOW_REQUEST_CODE: {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (!Settings.canDrawOverlays(registrar.context())) {
                        if (result != null) {
                            result.success(false);
                        }
                        return true;
                    }
                }
                if (result != null) {
                    result.success(false);
                }
            }
            break;
        }
        return false;
    }

    private class FloatingOnTouchListener implements View.OnTouchListener {
        private int  x;
        private int  y;
        private long ts;
        boolean moved = false;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    x = (int) event.getRawX();
                    y = (int) event.getRawY();
                    ts = System.currentTimeMillis();
                    moved = false;
                    break;
                case MotionEvent.ACTION_MOVE:
                    int nowX = (int) event.getRawX();
                    int nowY = (int) event.getRawY();
                    int movedX = nowX - x;
                    int movedY = nowY - y;
                    x = nowX;
                    y = nowY;
                    layoutParams.x = layoutParams.x + movedX;
                    layoutParams.y = layoutParams.y + movedY;
                    windowManager.updateViewLayout(view, layoutParams);
                    moved = true;
                    break;
                case MotionEvent.ACTION_UP:
                    if (System.currentTimeMillis() - ts < 300) {
                        registrar.context().startActivity(new Intent(registrar.context(), MainActivity.class));
                    }
                    break;
                default:
                    break;
            }
            return false;
        }
    }
}
