package com.warren.iwanttoheal;

import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;

@CapacitorPlugin(name = "DualScreen")
public class DualScreenPlugin extends Plugin {

    private TopDisplayPresentation presentation;

    @PluginMethod
    public void getDisplays(PluginCall call) {
        DisplayManager displayManager =
            (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
        Display currentDisplay = getActivity().getDisplay();
        JSArray displays = new JSArray();

        for (Display display : displayManager.getDisplays()) {
            displays.put(describeDisplay(display, currentDisplay));
        }

        JSObject result = new JSObject();
        result.put("currentDisplayId", currentDisplay == null ? -1 : currentDisplay.getDisplayId());
        result.put("displays", displays);
        call.resolve(result);
    }

    @PluginMethod
    public void openTopDisplay(PluginCall call) {
        getActivity().runOnUiThread(() -> {
            try {
                DisplayLaunchPlan launchPlan = createLaunchPlan(call.getInt("displayId"));
                if (launchPlan.targetDisplay == null) {
                    call.reject("No secondary Android display is available.");
                    return;
                }

                Display currentDisplay = getActivity().getDisplay();
                if (
                    currentDisplay != null
                    && currentDisplay.getDisplayId() == launchPlan.targetDisplay.getDisplayId()
                ) {
                    JSObject result = describeDisplay(currentDisplay, currentDisplay);
                    result.put("opened", true);
                    result.put("alreadyOnMainDisplay", true);
                    call.resolve(result);
                    return;
                }

                String gameUrl = bridge.getLocalUrl();
                String topGameUrl = gameUrl + "/?display=top";
                String controlsUrl = gameUrl + "/?display=bottom";
                String targetUrl = launchPlan.targetIsTopDisplay ? topGameUrl : controlsUrl;
                String currentUrl = launchPlan.currentIsTopDisplay ? topGameUrl : controlsUrl;

                closePresentation();
                presentation = new TopDisplayPresentation(
                    getActivity(),
                    launchPlan.targetDisplay,
                    targetUrl
                );
                presentation.setOnDismissListener(dialog -> {
                    presentation = null;
                    notifyListeners("displayDisconnected", new JSObject());
                });
                presentation.show();
                bridge.getWebView().loadUrl(currentUrl);

                JSObject result = describeDisplay(launchPlan.targetDisplay, getActivity().getDisplay());
                result.put("opened", true);
                result.put("presentationMode", true);
                result.put("targetIsTopDisplay", launchPlan.targetIsTopDisplay);
                result.put("currentIsTopDisplay", launchPlan.currentIsTopDisplay);
                call.resolve(result);
            } catch (Exception exception) {
                closePresentation();
                call.reject("Unable to open the upper display.", exception);
            }
        });
    }

    @PluginMethod
    public void closeTopDisplay(PluginCall call) {
        getActivity().runOnUiThread(() -> {
            closePresentation();
            call.resolve();
        });
    }

    @Override
    protected void handleOnDestroy() {
        closePresentation();
    }

    private DisplayLaunchPlan createLaunchPlan(Integer requestedDisplayId) {
        DisplayManager displayManager =
            (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
        Display currentDisplay = getActivity().getDisplay();
        int currentDisplayId = currentDisplay == null ? -1 : currentDisplay.getDisplayId();
        Display topDisplay = largestDisplay(displayManager.getDisplays());
        boolean currentIsTopDisplay =
            topDisplay != null && topDisplay.getDisplayId() == currentDisplayId;
        Display targetDisplay = null;

        if (requestedDisplayId != null) {
            Display requested = displayManager.getDisplay(requestedDisplayId);
            if (
                requested != null
                && requested.getDisplayId() != currentDisplayId
                && requested.getState() != Display.STATE_OFF
            ) {
                targetDisplay = requested;
            }
        }

        if (targetDisplay == null && currentIsTopDisplay) {
            targetDisplay = smallestOtherDisplay(displayManager.getDisplays(), currentDisplayId);
        }

        if (targetDisplay == null && topDisplay != null && topDisplay.getDisplayId() != currentDisplayId) {
            targetDisplay = topDisplay;
        }

        if (targetDisplay == null) {
            targetDisplay = largestOtherDisplay(
                displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION),
                currentDisplayId
            );
        }

        if (targetDisplay == null) {
            targetDisplay = largestOtherDisplay(displayManager.getDisplays(), currentDisplayId);
        }

        boolean targetIsTopDisplay =
            topDisplay != null && targetDisplay != null
                && targetDisplay.getDisplayId() == topDisplay.getDisplayId();
        return new DisplayLaunchPlan(targetDisplay, targetIsTopDisplay, currentIsTopDisplay);
    }

    private Display largestDisplay(Display[] displays) {
        Display selected = null;
        long selectedPixels = -1;
        for (Display display : displays) {
            if (display.getState() == Display.STATE_OFF) continue;
            long pixels = pixelCount(display);
            if (pixels > selectedPixels) {
                selected = display;
                selectedPixels = pixels;
            }
        }
        return selected;
    }

    private Display largestOtherDisplay(Display[] displays, int currentDisplayId) {
        Display selected = null;
        long selectedPixels = -1;
        for (Display display : displays) {
            if (
                display.getDisplayId() == currentDisplayId
                || display.getState() == Display.STATE_OFF
            ) {
                continue;
            }
            long pixels = pixelCount(display);
            if (pixels > selectedPixels) {
                selected = display;
                selectedPixels = pixels;
            }
        }
        return selected;
    }

    private Display smallestOtherDisplay(Display[] displays, int currentDisplayId) {
        Display selected = null;
        long selectedPixels = Long.MAX_VALUE;
        for (Display display : displays) {
            if (
                display.getDisplayId() == currentDisplayId
                || display.getState() == Display.STATE_OFF
            ) {
                continue;
            }
            long pixels = pixelCount(display);
            if (pixels < selectedPixels) {
                selected = display;
                selectedPixels = pixels;
            }
        }
        return selected;
    }

    private long pixelCount(Display display) {
        Display.Mode mode = display.getMode();
        return (long) mode.getPhysicalWidth() * mode.getPhysicalHeight();
    }

    private JSObject describeDisplay(Display display, Display currentDisplay) {
        Display.Mode mode = display.getMode();
        JSObject result = new JSObject();
        result.put("id", display.getDisplayId());
        result.put("name", display.getName());
        result.put("width", mode.getPhysicalWidth());
        result.put("height", mode.getPhysicalHeight());
        result.put("refreshRate", mode.getRefreshRate());
        result.put(
            "isCurrent",
            currentDisplay != null && currentDisplay.getDisplayId() == display.getDisplayId()
        );
        result.put(
            "isPresentation",
            (display.getFlags() & Display.FLAG_PRESENTATION) == Display.FLAG_PRESENTATION
        );
        return result;
    }

    private void closePresentation() {
        if (presentation == null) return;
        presentation.setOnDismissListener(null);
        presentation.dismiss();
        presentation = null;
    }

    private final class DisplayLaunchPlan {

        private final Display targetDisplay;
        private final boolean targetIsTopDisplay;
        private final boolean currentIsTopDisplay;

        DisplayLaunchPlan(
            Display targetDisplay,
            boolean targetIsTopDisplay,
            boolean currentIsTopDisplay
        ) {
            this.targetDisplay = targetDisplay;
            this.targetIsTopDisplay = targetIsTopDisplay;
            this.currentIsTopDisplay = currentIsTopDisplay;
        }
    }

    private final class TopDisplayPresentation extends Presentation {

        private final String initialUrl;
        private final Display display;

        TopDisplayPresentation(Context context, Display display, String initialUrl) {
            super(context, display);
            this.display = display;
            this.initialUrl = initialUrl;
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().setBackgroundDrawableResource(android.R.color.black);
            getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            );
            AndroidDisplayPerformance.preferBatteryRefreshRate(getWindow(), display);

            FrameLayout container = new FrameLayout(getContext());
            container.setBackgroundColor(Color.BLACK);
            WebView webView = new WebView(getContext());
            configureWebView(webView);
            container.addView(
                webView,
                new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
            );
            setContentView(container);
            webView.loadUrl(initialUrl);
        }
    }

    private void configureWebView(WebView webView) {
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        settings.setDatabaseEnabled(true);
        settings.setMediaPlaybackRequiresUserGesture(false);
        settings.setAllowFileAccess(true);
        settings.setAllowContentAccess(true);
        webView.setBackgroundColor(Color.BLACK);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(
                WebView view,
                WebResourceRequest request
            ) {
                return bridge.getLocalServer().shouldInterceptRequest(request);
            }
        });
    }
}
