package com.ttstd.controlled.input;

import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;

import java.lang.reflect.Method;

/**
 * 使用系统隐藏 API android.hardware.input.InputManager 进行事件注入的实现类。
 * 需要应用具有系统签名 (android:sharedUserId="android.uid.system") 和 INJECT_EVENTS 权限。
 */
public class SystemInputUtils implements InputExecutor {
    private static final String TAG = "SystemInputUtils";

    private Object mInputManager;
    private Method mInjectInputEventMethod;
    private static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0;
    private static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
    private long mDownTime;

    public SystemInputUtils() {
        try {
            // 反射获取 InputManager 实例
            Class<?> inputManagerClass = Class.forName("android.hardware.input.InputManager");
            Method getInstanceMethod = inputManagerClass.getDeclaredMethod("getInstance");
            mInputManager = getInstanceMethod.invoke(null);

            // 获取 injectInputEvent 方法
            mInjectInputEventMethod = inputManagerClass.getMethod("injectInputEvent", InputEvent.class, int.class);
        } catch (Exception e) {
            Log.e(TAG, "Failed to initialize SystemInputUtils via reflection", e);
        }
    }

    @Override
    public void injectTap(int x, int y) {
        long downTime = SystemClock.uptimeMillis();
        injectMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, x, y);
        injectMotionEvent(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y);
    }

    @Override
    public void injectLongPress(int x, int y) {
        long downTime = SystemClock.uptimeMillis();
        injectMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, x, y);
        // 模拟长按等待
        SystemClock.sleep(1000);
        injectMotionEvent(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y);
    }

    @Override
    public void injectSwipe(int x1, int y1, int x2, int y2, long duration) {
//        long downTime = SystemClock.uptimeMillis();
//        injectMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, x1, y1);
//
//        int steps = 10;
//        for (int i = 1; i <= steps; i++) {
//            SystemClock.sleep(duration / steps);
//            int x = x1 + (x2 - x1) * i / steps;
//            int y = y1 + (y2 - y1) * i / steps;
//            injectMotionEvent(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, x, y);
//        }
//
//        injectMotionEvent(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x2, y2);
    }

    @Override
    public void injectKeyEvent(int keyCode) {
        long now = SystemClock.uptimeMillis();
        injectKeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode);
        injectKeyEvent(now, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keyCode);
    }

    @Override
    public void injectMotionEvent(int action, int x, int y) {
        long now = SystemClock.uptimeMillis();
        if (action == MotionEvent.ACTION_DOWN) {
            mDownTime = now;
        }
        injectMotionEvent(mDownTime, now, action, x, y);
    }

    private void injectMotionEvent(long downTime, long eventTime, int action, float x, float y) {
        MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
        event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
        try {
            mInjectInputEventMethod.invoke(mInputManager, event, INJECT_INPUT_EVENT_MODE_ASYNC);
        } catch (Exception e) {
            Log.e(TAG, "Error injecting motion event", e);
        } finally {
            event.recycle();
        }
    }

    private void injectKeyEvent(long downTime, long eventTime, int action, int keyCode) {
        KeyEvent event = new KeyEvent(downTime, eventTime, action, keyCode, 0);
        try {
            mInjectInputEventMethod.invoke(mInputManager, event, INJECT_INPUT_EVENT_MODE_ASYNC);
        } catch (Exception e) {
            Log.e(TAG, "Error injecting key event", e);
        }
    }
}
