package com.ajinasokan.flutterdisplaymode;

import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import java.util.ArrayList;
import java.util.HashMap;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/**
 * DisplayModePlugin
 */
public class DisplayModePlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
    private Activity activity;
    private static final String METHOD_GET_ACTIVE_MODE = "getActiveMode";
    private static final String METHOD_GET_SUPPORTED_MODES = "getSupportedModes";
    private static final String METHOD_GET_PREFERRED_MODE = "getPreferredMode";
    private static final String METHOD_SET_PREFERRED_MODE = "setPreferredMode";

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        final MethodChannel channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_display_mode");
        channel.setMethodCallHandler(this);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            result.error("noAPI", "API is supported only in Android 6 (Marshmallow) and later", null);
            return;
        }

        if (activity == null) {
            result.error("noActivity", "Activity not attached to plugin. App is probably in background.", null);
            return;
        }

        switch (call.method) {
            case METHOD_GET_ACTIVE_MODE:
                getActiveMode(result);
                break;
            case METHOD_GET_SUPPORTED_MODES:
                getSupportedModes(result);
                break;
            case METHOD_GET_PREFERRED_MODE:
                getPreferredMode(result);
                break;
            case METHOD_SET_PREFERRED_MODE:
                setPreferredMode(call, result);
                break;
            default:
                result.notImplemented();
                break;
        }
    }

    @SuppressWarnings("deprecation")
    Display getDisplay() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            return activity.getDisplay();
        } else {
            final WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
            return windowManager.getDefaultDisplay();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void getActiveMode(@NonNull Result result) {
        final Display.Mode mode = getDisplay().getMode();
        final HashMap<String, Object> ret = new HashMap<>();
        ret.put("id", mode.getModeId());
        ret.put("width", mode.getPhysicalWidth());
        ret.put("height", mode.getPhysicalHeight());
        ret.put("refreshRate", mode.getRefreshRate());
        result.success(ret);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private ArrayList<HashMap<String, Object>> getSupportedModes() {
        final ArrayList<HashMap<String, Object>> ret = new ArrayList<>();
        final Display display = getDisplay();
        final Display.Mode[] modes = display.getSupportedModes();

        for (final Display.Mode mode : modes) {
            final HashMap<String, Object> item = new HashMap<>();
            item.put("id", mode.getModeId());
            item.put("width", mode.getPhysicalWidth());
            item.put("height", mode.getPhysicalHeight());
            item.put("refreshRate", mode.getRefreshRate());
            ret.add(item);
        }
        return ret;
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void getSupportedModes(@NonNull Result result) {
        result.success(getSupportedModes());
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void getPreferredMode(@NonNull Result result) {
        final Window window = activity.getWindow();
        final WindowManager.LayoutParams params = window.getAttributes();

        final Display display = getDisplay();
        final Display.Mode[] modes = display.getSupportedModes();

        // look for matching mode and return it
        for (final Display.Mode mode : modes) {
            if (params.preferredDisplayModeId == mode.getModeId()) {
                final HashMap<String, Object> item = new HashMap<>();
                item.put("id", mode.getModeId());
                item.put("width", mode.getPhysicalWidth());
                item.put("height", mode.getPhysicalHeight());
                item.put("refreshRate", mode.getRefreshRate());
                result.success(item);
                return;
            }
        }

        // no match found. return as automatic
        final HashMap<String, Object> ret = new HashMap<>();
        ret.put("id", 0);
        ret.put("width", 0);
        ret.put("height", 0);
        ret.put("refreshRate", 0.0);
        result.success(ret);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void setPreferredMode(@NonNull MethodCall call, @NonNull Result result) {
        final int mode = call.argument("mode");
        final Window window = activity.getWindow();
        final WindowManager.LayoutParams params = window.getAttributes();
        params.preferredDisplayModeId = mode;
        window.setAttributes(params);
        result.success(null);
    }

    private void setActivity(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        activity = binding.getActivity();
    }

    @Override
    public void onDetachedFromActivity() {
        activity = null;
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {
        onDetachedFromActivity();
    }

    @Override
    public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
        onAttachedToActivity(binding);
    }
}
