package com.izouma.screen_stream_plugin;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;

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

import static android.content.Context.MEDIA_PROJECTION_SERVICE;
import static android.content.Context.WINDOW_SERVICE;

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
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 MethodChannel.Result   result;
    private MediaProjectionManager mediaProjectionManager;

    private WindowManager              windowManager;
    private WindowManager.LayoutParams layoutParams;
    private ImageButton                floatButton;
    private int                        playerInfoId;

    private VideoProcessService.VideoProcessBinder videoProcessBinder;

    private String dialogMessage;

    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("APP_LIFECYCLE_ACTION"));

        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 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 42, registrar.activity().getResources().getDisplayMetrics());
        layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, registrar.activity().getResources().getDisplayMetrics());
        layoutParams.x = 500;
        layoutParams.y = 40;
        // showFloatWindow();
    }

    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        this.result = result;
        if ("start".equals(methodCall.method)) {
            playerInfoId = Integer.parseInt(Objects.requireNonNull(methodCall.argument("playerInfoId")));
            mediaProjectionManager = (MediaProjectionManager) registrar.activeContext().getSystemService(MEDIA_PROJECTION_SERVICE);
            registrar.activity().startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), CAPTURE_PERMISSION_REQUEST_CODE);
            if (methodCall.argument("dialogMessage") != null) {
                dialogMessage = methodCall.argument("dialogMessage");
            }
        } 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();
        } else if ("getVideo".equals(methodCall.method)) {
            String video = getVideo(methodCall.argument("playerInfoId"));
            result.success(video);
        }
    }

    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 String getVideo(String playerInfoId) {
        SharedPreferences sharedPreferences = registrar.context().getApplicationContext().getSharedPreferences(registrar.context().getApplicationContext().getPackageName(), Context.MODE_PRIVATE);
        String jsonStr = sharedPreferences.getString("video", "{}");
        try {
            JSONObject jsonObject = new JSONObject(jsonStr);
            return jsonObject.getString(playerInfoId);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void showFloatWindow() {
        if (floatButton != null) {
            return;
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(registrar.context())) {
            floatButton = new ImageButton(registrar.context().getApplicationContext());
            floatButton.setAlpha(0.5f);
            floatButton.setPadding(0, 0, 0, 0);
            floatButton.setScaleType(ImageView.ScaleType.CENTER_CROP);
            floatButton.setImageResource(R.mipmap.icon_float_button);
            floatButton.setBackgroundColor(Color.TRANSPARENT);
            floatButton.setVisibility(View.GONE);
            windowManager.addView(floatButton, layoutParams);
            floatButton.setOnTouchListener(new FloatingOnTouchListener());
            floatButton.setOnClickListener(v -> {
                floatButton.setEnabled(false);
                Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        registrar.activity().runOnUiThread(() -> floatButton.setEnabled(true));
                    }
                }, 500);
                showCustomPopupMenu();
            });
        }
    }

    private boolean stop() {
        if (floatButton != null) {
            windowManager.removeView(floatButton);
            floatButton = null;
        }
        if (videoProcessBinder != null) {
            videoProcessBinder.stop();
        }
        return true;
    }

    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case CAPTURE_PERMISSION_REQUEST_CODE: {
                if (resultCode == Activity.RESULT_OK) {
                    Intent intent = new Intent(registrar.context(), VideoProcessService.class);
                    registrar.activity().startService(intent);
                    if (videoProcessBinder == null) {
                        registrar.activity().bindService(intent, new ServiceConnection() {
                            @Override
                            public void onServiceConnected(ComponentName name, IBinder service) {
                                videoProcessBinder = (VideoProcessService.VideoProcessBinder) service;
                                videoProcessBinder.start(mediaProjectionManager.getMediaProjection(resultCode, data), playerInfoId);
                            }

                            @Override
                            public void onServiceDisconnected(ComponentName name) {
                                videoProcessBinder = null;
                            }
                        }, Context.BIND_IMPORTANT);
                    } else {
                        videoProcessBinder.start(mediaProjectionManager.getMediaProjection(resultCode, data), playerInfoId);
                    }
                    showFloatWindow();
                    result.success(true);
                    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:
                    floatButton.setAlpha(1f);
                    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:
                    makeTranslucent();
                    break;
                default:
                    break;
            }
            return false;
        }
    }

    public static String getApplicationName(Context context) {
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        int stringId = applicationInfo.labelRes;
        return stringId == 0 ? applicationInfo.nonLocalizedLabel.toString() : context.getString(stringId);
    }

    private void showCustomPopupMenu() {
        LayoutInflater layoutInflater = (LayoutInflater) this.registrar.context().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View dialogOverlay = layoutInflater.inflate(R.layout.dialog, null);
        dialogOverlay.findViewById(R.id.btn_cancel).setOnClickListener(v -> {
            windowManager.removeView(dialogOverlay);
        });
        dialogOverlay.findViewById(R.id.btn_ok).setOnClickListener(v -> {
            windowManager.removeView(dialogOverlay);
            Intent intent = new Intent(registrar.context().getApplicationContext(), registrar.activity().getClass());
            intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            registrar.activity().startActivity(intent);
        });

        ((TextView) dialogOverlay.findViewById(R.id.tv_msg)).setText(TextUtils.isEmpty(dialogMessage) ? "是否立即返回" + getApplicationName(registrar.context()) + "？" : dialogMessage);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            params.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        params.format = PixelFormat.RGBA_8888;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        params.gravity = Gravity.CENTER;
        windowManager.addView(dialogOverlay, params);
    }

    private Timer timer;

    private void makeTranslucent() {
        if (timer != null) {
            timer.cancel();
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                registrar.activity().runOnUiThread(() -> floatButton.setAlpha(0.5f));
                timer = null;
            }
        }, 2000);
    }
}
