package com.phenomrom.iwanttoheal;

import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
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;

/** Keeps a dedicated WebView visible on each AYN Thor panel for the activity lifetime. */
@CapacitorPlugin(name = "ThorDualScreen")
public class ThorDualScreenPlugin extends Plugin implements DisplayManager.DisplayListener {
    private final Handler handler = new Handler(Looper.getMainLooper());
    private DisplayManager displayManager;
    private ThorPresentation presentation;
    private boolean forceEnabled;

    @Override
    public void load() {
        displayManager = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
        displayManager.registerDisplayListener(this, handler);
    }

    @PluginMethod
    public void getDisplays(PluginCall call) {
        Display current = currentDisplay();
        JSArray displays = new JSArray();
        for (Display display : displayManager.getDisplays()) displays.put(describeDisplay(display, current));
        JSObject result = new JSObject();
        result.put("currentDisplayId", current == null ? -1 : current.getDisplayId());
        result.put("displays", displays);
        call.resolve(result);
    }

    @PluginMethod
    public void forceBothDisplays(PluginCall call) {
        forceEnabled = true;
        getActivity().runOnUiThread(() -> {
            try {
                DisplayPlan plan = createPlan();
                if (plan.target == null) {
                    call.reject("No active secondary Android display is available.");
                    return;
                }
                boolean alreadyOpen = presentation != null
                    && presentation.isShowing()
                    && presentation.getDisplay().getDisplayId() == plan.target.getDisplayId();
                if (!alreadyOpen) openPlan(plan);
                JSObject result = describeDisplay(plan.target, currentDisplay());
                result.put("opened", true);
                result.put("topOnActivity", plan.currentIsTop);
                call.resolve(result);
            } catch (Exception exception) {
                closePresentation();
                call.reject("Unable to force both Thor displays.", exception);
            }
        });
    }

    @Override
    protected void handleOnResume() {
        if (forceEnabled) scheduleEnsurePresentation(0L);
    }

    @Override
    protected void handleOnDestroy() {
        forceEnabled = false;
        if (displayManager != null) displayManager.unregisterDisplayListener(this);
        handler.removeCallbacksAndMessages(null);
        closePresentation();
    }

    @Override
    public void onDisplayAdded(int displayId) {
        if (forceEnabled) scheduleEnsurePresentation(100L);
    }

    @Override
    public void onDisplayRemoved(int displayId) {
        if (presentation != null && presentation.getDisplay().getDisplayId() == displayId) {
            closePresentation();
        }
        if (forceEnabled) scheduleEnsurePresentation(250L);
    }

    @Override
    public void onDisplayChanged(int displayId) {
        if (forceEnabled) scheduleEnsurePresentation(100L);
    }

    private void scheduleEnsurePresentation(long delayMs) {
        handler.removeCallbacks(ensurePresentation);
        handler.postDelayed(ensurePresentation, delayMs);
    }

    private final Runnable ensurePresentation = () -> {
        if (!forceEnabled || getActivity() == null || getActivity().isFinishing()) return;
        DisplayPlan plan = createPlan();
        if (plan.target == null) return;
        if (
            presentation != null
                && presentation.isShowing()
                && presentation.getDisplay().getDisplayId() == plan.target.getDisplayId()
        ) return;
        openPlan(plan);
    };

    private void openPlan(DisplayPlan plan) {
        String baseUrl = bridge.getLocalUrl();
        String targetUrl = baseUrl + "/?display=" + (plan.targetIsTop ? "top" : "bottom") + "&role=presentation";
        String currentUrl = baseUrl + "/?display=" + (plan.currentIsTop ? "top" : "bottom") + "&role=activity";
        closePresentation();
        presentation = new ThorPresentation(
            getActivity(),
            plan.target,
            targetUrl
        );
        presentation.setOnDismissListener(dialog -> {
            presentation = null;
            notifyListeners("displayDisconnected", new JSObject());
            if (forceEnabled) scheduleEnsurePresentation(300L);
        });
        presentation.show();
        bridge.getWebView().loadUrl(currentUrl);
    }

    private DisplayPlan createPlan() {
        Display current = currentDisplay();
        int currentId = current == null ? -1 : current.getDisplayId();
        Display[] displays = displayManager.getDisplays();
        Display top = largestDisplay(displays);
        boolean currentIsTop = top != null && top.getDisplayId() == currentId;
        Display target = currentIsTop
            ? smallestOtherDisplay(displays, currentId)
            : top != null && top.getDisplayId() != currentId ? top : largestOtherDisplay(displays, currentId);
        boolean targetIsTop = target != null && top != null && target.getDisplayId() == top.getDisplayId();
        return new DisplayPlan(target, targetIsTop, currentIsTop);
    }

    private Display currentDisplay() {
        return getActivity().getWindow().getDecorView().getDisplay();
    }

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

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

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

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

    private JSObject describeDisplay(Display display, Display current) {
        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", current != null && current.getDisplayId() == display.getDisplayId());
        return result;
    }

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

    private final class ThorPresentation extends Presentation {
        private final String initialUrl;
        private WebView webView;

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

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().setBackgroundDrawableResource(android.R.color.black);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
            WindowManager.LayoutParams attributes = getWindow().getAttributes();
            attributes.preferredRefreshRate = 60.0f;
            getWindow().setAttributes(attributes);
            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
            );

            FrameLayout container = new FrameLayout(getContext());
            container.setBackgroundColor(Color.BLACK);
            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);
        }

        @Override
        protected void onStop() {
            super.onStop();
            if (webView != null) {
                webView.stopLoading();
                webView.destroy();
                webView = null;
            }
        }
    }

    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.setOverScrollMode(View.OVER_SCROLL_NEVER);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                return bridge.getLocalServer().shouldInterceptRequest(request);
            }
        });
    }

    private static final class DisplayPlan {
        private final Display target;
        private final boolean targetIsTop;
        private final boolean currentIsTop;

        DisplayPlan(Display target, boolean targetIsTop, boolean currentIsTop) {
            this.target = target;
            this.targetIsTop = targetIsTop;
            this.currentIsTop = currentIsTop;
        }
    }
}
