package com.drmod;

import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ToggleButton;

public class Overlay {
    private static final String TAG = "DRMod-Overlay";
    private static native void nativeToggle(int feature, boolean enabled);

    // Stato condiviso: [0]=menu aperto, [1]=overlay nascosto (hitbox solo tocco)
    public static void init(final Context ctx) {
        DLog.log(TAG, "init() entered, ctx=" + (ctx != null ? ctx.getClass().getName() : "null"));
        try {
            if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(ctx)) {
                DLog.log(TAG, "canDrawOverlays=false, attempting anyway");
            } else {
                DLog.log(TAG, "canDrawOverlays=true");
            }
        } catch (Throwable t) {
            DLog.log(TAG, "Permission check failed: " + t.getMessage());
        }

        final Context themedCtx = new ContextThemeWrapper(ctx, android.R.style.Theme_DeviceDefault);
        final WindowManager wm = (WindowManager) themedCtx.getSystemService(Context.WINDOW_SERVICE);
        DLog.log(TAG, "themedCtx created, wm=" + (wm != null ? "ok" : "NULL"));

        // ===== Menu (contenuto, liberamente trascinabile) =====
        final LinearLayout menu = new LinearLayout(themedCtx);
        menu.setOrientation(LinearLayout.VERTICAL);
        menu.setBackgroundColor(0xCC111111);
        menu.setPadding(dp(themedCtx, 12), dp(themedCtx, 12), dp(themedCtx, 12), dp(themedCtx, 12));

        TextView title = new TextView(themedCtx);
        title.setText("DungeonRush Mod");
        title.setTextColor(Color.WHITE);
        title.setTextSize(14);
        title.setPadding(0, 0, 0, dp(themedCtx, 2));
        menu.addView(title);

        TextView sub = new TextView(themedCtx);
        sub.setText(" by TeamModdersITA");
        sub.setTextColor(0xFF999999);
        sub.setTextSize(10);
        sub.setPadding(0, 0, 0, dp(themedCtx, 8));
        menu.addView(sub);

        String[] names = {"Immortality", "Forced Crits", "Divine Forge", "Divine Overdrive", "Minigame Loot", "Forge Exp Substats"};
        for (int i = 0; i < names.length; i++) {
            final int idx = i;
            ToggleButton btn = new ToggleButton(themedCtx);
            btn.setTextOn(names[i] + " [ON]");
            btn.setTextOff(names[i] + " [OFF]");
            btn.setChecked(false);
            btn.setTextSize(11);
            btn.setBackgroundColor(0xFF222222);
            btn.setTextColor(Color.WHITE);
            btn.setPadding(dp(themedCtx, 8), dp(themedCtx, 4), dp(themedCtx, 8), dp(themedCtx, 4));
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
            lp.bottomMargin = dp(themedCtx, 4);
            btn.setLayoutParams(lp);
            btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton v, boolean checked) {
                    nativeToggle(idx, checked);
                }
            });
            menu.addView(btn);
        }

        TextView sep = new TextView(themedCtx);
        sep.setText("\nAlways ON:");
        sep.setTextColor(0xFF888888);
        sep.setTextSize(10);
        menu.addView(sep);

        TextView status = new TextView(themedCtx);
        status.setText("  Ad Skip\n  Store Bypass\n  ACTk Disable");
        status.setTextColor(0xFF666666);
        status.setTextSize(10);
        menu.addView(status);

        DLog.log(TAG, "menu built with " + names.length + " toggles");

        // ===== FAB (ancora fissa, separata dal menu) =====
        final Button fab = new Button(themedCtx);
        fab.setText("DR");
        fab.setTextSize(10);
        fab.setBackgroundColor(0xAAFF3333);
        fab.setTextColor(Color.WHITE);
        fab.setPadding(0, 0, 0, 0);
        fab.setMinWidth(dp(themedCtx, 40));
        fab.setMinimumWidth(dp(themedCtx, 40));
        fab.setMinHeight(dp(themedCtx, 40));
        fab.setMinimumHeight(dp(themedCtx, 40));

        // Wrapper separati, ognuno è una view indipendente agganciata al decor.
        final FrameLayout menuRoot = new FrameLayout(themedCtx);
        menuRoot.addView(menu, new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT));

        final FrameLayout fabRoot = new FrameLayout(themedCtx);
        fabRoot.addView(fab, new FrameLayout.LayoutParams(
            dp(themedCtx, 44), dp(themedCtx, 44)));
        DLog.log(TAG, "menuRoot + fabRoot built (separate)");

        // Stato: [0]=menu aperto, [1]=nascosto (fab alpha 0 ma toccabile)
        final boolean[] state = {false, false};

        // Apertura/chiusura menu con doppio click sul FAB? No: click singolo.
        fab.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                state[1] = false; // riprende da hide comunque
                state[0] = !state[0];
                if (state[0]) {
                    // Rendi visibile il menu e posizionalo accanto al FAB (dimensioni fisse).
                    menuRoot.setVisibility(View.VISIBLE);
                    placeMenuNearFab(menuRoot, fabRoot, themedCtx);
                    fabRoot.setVisibility(View.GONE); // overlay sparisce quando menu aperto
                } else {
                    menuRoot.setVisibility(View.GONE);
                    fabRoot.setVisibility(View.VISIBLE);
                    fab.setAlpha(1f);
                }
            }
        });

        // Drag separati: il menu sposta solo menuRoot, il fab sposta solo fabRoot.
        makeDraggable(menu, menuRoot, state);
        makeDraggable(fab, fabRoot, state);
        DLog.log(TAG, "draggable set (menu->menuRoot, fab->fabRoot)");

        // Bottoni hide/close (vivono nel menu e agiscono su menuRoot + fab)
        buildButtons(menu, menuRoot, fabRoot, fab, state, themedCtx);

        // All'avvio il menu è nascosto; il FAB resta l'ancora visibile per aprirlo.
        menuRoot.setVisibility(View.GONE);

        DLog.log(TAG, "scheduling addView on main looper...");
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                DLog.log(TAG, "addView runnable started on thread="
                    + Thread.currentThread().getName());
                boolean attached = false;
                try {
                    attached = attachToActivityDecor(menuRoot, fabRoot, themedCtx);
                    DLog.log(TAG, "attachToActivityDecor=" + attached);
                } catch (Throwable t) {
                    DLog.log(TAG, "attachToActivityDecor exception: " + t);
                }
                if (!attached) {
                    try {
                        WindowManager.LayoutParams mParams = makeWmParams(themedCtx);
                        WindowManager.LayoutParams fParams = makeWmParams(themedCtx);
                        fParams.y = dp(themedCtx, 100);
                        wm.addView(menuRoot, mParams);
                        wm.addView(fabRoot, fParams);
                        DLog.log(TAG, "wm.addView fallback succeeded (menu+fab)");
                    } catch (Throwable t) {
                        DLog.log(TAG, "wm.addView fallback failed: " + t);
                    }
                }
            }
        });
        DLog.log(TAG, "init() complete");
    }

    // ===== Punto di aggancio al decor =====
    private static boolean attachToActivityDecor(View menuChild, View fabChild, Context ctx) {
        try {
            Class<?> atCls = Class.forName("android.app.ActivityThread");
            Object at = atCls.getMethod("currentActivityThread").invoke(null);
            if (at == null) {
                DLog.log(TAG, "attach: ActivityThread null");
                return false;
            }
            java.lang.reflect.Field mActivities =
                atCls.getDeclaredField("mActivities");
            mActivities.setAccessible(true);
            Object activities = mActivities.get(at);
            DLog.log(TAG, "attach: mActivities=" + activities);
            if (activities == null) return false;

            Object record = null;
            if (activities instanceof java.util.Map) {
                java.util.Collection<?> vals =
                    ((java.util.Map<?, ?>) activities).values();
                if (!vals.isEmpty()) {
                    record = vals.iterator().next();
                }
            }
            DLog.log(TAG, "attach: record=" + record);
            if (record == null) return false;

            java.lang.reflect.Field actField =
                record.getClass().getDeclaredField("activity");
            actField.setAccessible(true);
            Object activity = actField.get(record);
            DLog.log(TAG, "attach: activity=" + activity);
            if (!(activity instanceof android.app.Activity)) return false;

            android.view.ViewGroup decor =
                (android.view.ViewGroup) ((android.app.Activity) activity)
                    .getWindow().getDecorView();
            DLog.log(TAG, "attach: decor=" + decor);

            // Menu: default in alto a sinistra, indipendente.
            android.widget.FrameLayout.LayoutParams mLp =
                new android.widget.FrameLayout.LayoutParams(
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
                    android.view.Gravity.TOP | android.view.Gravity.START);
            mLp.topMargin = dp(ctx, 120);
            mLp.leftMargin = dp(ctx, 60);

            // FAB: ancorato in alto a sinistra (dove l'ho aperto), indipendente.
            android.widget.FrameLayout.LayoutParams fLp =
                new android.widget.FrameLayout.LayoutParams(
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
                    android.view.Gravity.TOP | android.view.Gravity.START);
            fLp.topMargin = dp(ctx, 100);
            fLp.leftMargin = dp(ctx, 8);

            decor.addView(menuChild, mLp);
            decor.addView(fabChild, fLp);
            DLog.log(TAG, "attach: menu+fab attached to decor");
            return true;
        } catch (Throwable t) {
            DLog.log(TAG, "attachToActivityDecor exception: " + t);
            return false;
        }
    }

    private static WindowManager.LayoutParams makeWmParams(Context ctx) {
        int overlayType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        if (Build.VERSION.SDK_INT < 26) {
            overlayType = WindowManager.LayoutParams.TYPE_PHONE;
        }
        WindowManager.LayoutParams p = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            overlayType,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
            PixelFormat.TRANSLUCENT);
        p.gravity = Gravity.TOP | Gravity.START;
        p.x = dp(ctx, 8);
        p.y = dp(ctx, 100);
        return p;
    }

    // ===== Hide / Close =====
    private static void buildButtons(final LinearLayout menu, final FrameLayout menuRoot,
            final FrameLayout fabRoot, final Button fab, final boolean[] state, Context ctx) {
        try {
            LinearLayout btnRow = new LinearLayout(ctx);
            btnRow.setOrientation(LinearLayout.HORIZONTAL);
            LinearLayout.LayoutParams rowLp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
            rowLp.topMargin = dp(ctx, 4);
            btnRow.setLayoutParams(rowLp);

            Button hideBtn = new Button(ctx);
            hideBtn.setText("hide");
            hideBtn.setTextSize(11);
            hideBtn.setBackgroundColor(0xFF222222);
            hideBtn.setTextColor(Color.WHITE);

            Button closeBtn = new Button(ctx);
            closeBtn.setText("close");
            closeBtn.setTextSize(11);
            closeBtn.setBackgroundColor(0xFF222222);
            closeBtn.setTextColor(Color.WHITE);

            btnRow.addView(hideBtn, new LinearLayout.LayoutParams(
                0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
            btnRow.addView(closeBtn, new LinearLayout.LayoutParams(
                0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
            menu.addView(btnRow);

            hideBtn.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    state[0] = false;
                    state[1] = true;
                    menuRoot.setVisibility(View.GONE);
                    fabRoot.setVisibility(View.VISIBLE);
                    fab.setAlpha(0f); // ancora nascosta ma toccabile per riaprire
                }
            });

            closeBtn.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    state[0] = false;
                    state[1] = false;
                    menuRoot.setVisibility(View.GONE);
                    fabRoot.setVisibility(View.VISIBLE);
                    fab.setAlpha(1f);
                }
            });
            DLog.log(TAG, "hide/close listeners attached");
        } catch (Throwable t) {
            DLog.log(TAG, "buildButtons EXCEPTION: " + t);
        }
    }

    // ===== Drag: sposta SOLO il view indicato (moveView), clamp + size fissa =====
    private static void makeDraggable(final View touchView, final View moveView,
            final boolean[] state) {
        touchView.setOnTouchListener(new View.OnTouchListener() {
            int lastX, lastY;
            boolean moved;
            public boolean onTouch(View v, MotionEvent event) {
                if (state[1]) return false;
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        lastX = (int) event.getRawX();
                        lastY = (int) event.getRawY();
                        moved = false;
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        int dx = (int) event.getRawX() - lastX;
                        int dy = (int) event.getRawY() - lastY;
                        if (Math.abs(dx) > 5 || Math.abs(dy) > 5) moved = true;
                        lastX = (int) event.getRawX();
                        lastY = (int) event.getRawY();
                        if (moveView.getParent() != null) {
                            moveClamped(moveView, dx, dy);
                        }
                        return true;
                    case MotionEvent.ACTION_UP:
                        if (!moved) {
                            v.performClick();
                        }
                        return moved;
                }
                return false;
            }
        });
        DLog.log(TAG, "draggable attached: touch=" + touchView.getClass().getSimpleName()
            + " move=" + moveView.getClass().getSimpleName());
    }

    // Sposta il view con: size fissa (no rimpicciolimento AT_MOST) + clamp a schermo.
    private static void moveClamped(View view, int dx, int dy) {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
            view.setTranslationX(view.getTranslationX() + dx);
            view.setTranslationY(view.getTranslationY() + dy);
            return;
        }
        ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
        int w = view.getWidth();
        int h = view.getHeight();
        if (w <= 0) w = view.getMeasuredWidth();
        if (h <= 0) h = view.getMeasuredHeight();
        boolean known = (w > 0 && h > 0);
        if (known) {
            mlp.width = w;
            mlp.height = h;
        }
        int left = mlp.leftMargin + dx;
        int top = mlp.topMargin + dy;
        View parent = (View) view.getParent();
        if (parent != null) {
            int parentW = parent.getWidth();
            int parentH = parent.getHeight();
            left = Math.max(0, left);
            top = Math.max(0, top);
            if (known && parentW > 0) left = Math.min(left, Math.max(0, parentW - w));
            if (known && parentH > 0) top = Math.min(top, Math.max(0, parentH - h));
        } else {
            if (left < 0) left = 0;
            if (top < 0) top = 0;
        }
        mlp.leftMargin = left;
        mlp.topMargin = top;
        view.setLayoutParams(mlp);
    }

    // Posiziona il menu accanto al FAB (a destra se c'è spazio, altrimenti a sinistra),
    // sempre con clamp a schermo.
    private static void placeMenuNearFab(View menuRoot, View fabRoot, Context ctx) {
        ViewGroup.LayoutParams mlp0 = menuRoot.getLayoutParams();
        ViewGroup.LayoutParams flp0 = fabRoot.getLayoutParams();
        int fx = 8, fy = 100;
        if (flp0 instanceof ViewGroup.MarginLayoutParams) {
            ViewGroup.MarginLayoutParams f = (ViewGroup.MarginLayoutParams) flp0;
            fx = f.leftMargin;
            fy = f.topMargin;
        }
        int fw = fabRoot.getWidth();
        if (fw <= 0) fw = dp(ctx, 44);

        int screenW = ctx.getResources().getDisplayMetrics().widthPixels;
        int screenH = ctx.getResources().getDisplayMetrics().heightPixels;

        // Dimensioni del menu hardcodate (calibrate a schermo 720x1448 dalla misurazione reale).
        // Non serve misurare né aprire invisibile: usiamo direttamente i valori fissi.
        int mw = 350;
        int mh = 771;

        int left = fx + fw;
        int top = fy;
        if (left + mw > screenW) left = fx - mw; // a sinistra del fab se non c'è spazio
        left = Math.max(0, left);
        top = Math.max(0, top);
        if (left + mw > screenW) left = Math.max(0, screenW - mw);
        if (top + mh > screenH) top = Math.max(0, screenH - mh);

        if (mlp0 instanceof ViewGroup.MarginLayoutParams) {
            ViewGroup.MarginLayoutParams m = (ViewGroup.MarginLayoutParams) mlp0;
            m.leftMargin = left;
            m.topMargin = top;
            menuRoot.setLayoutParams(m);
        }
        DLog.log(TAG, "placeMenuNearFab -> left=" + left + " top=" + top + " mw=" + mw + " mh=" + mh);
    }

    private static int dp(Context ctx, int val) {
        return (int) (val * ctx.getResources().getDisplayMetrics().density);
    }
}
