#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>
#include "H5View.h"
extern UIView *UnityGetGLView(void);

@interface UIApplication (UnityTouchHook)
- (void)ut_sendEvent:(UIEvent *)event;
@end

@implementation UIApplication (UnityTouchHook)

// ==========================================
// 【实装优化】：将 Ivar、Class 提取为静态全局变量，在 +load 中一次性缓存
static CFTimeInterval g_lastMovedTime = 0;
static Class g_touchClass = Nil;
static Ivar g_ivarView = NULL;
static Ivar g_ivarLocation = NULL;
static Ivar g_ivarPrevLocation = NULL;
// ==========================================

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = [UIApplication class];
        Method original = class_getInstanceMethod(cls, @selector(sendEvent:));
        Method swizzled = class_getInstanceMethod(cls, @selector(ut_sendEvent:));

        if (original && swizzled) {
            method_exchangeImplementations(original, swizzled);
        }
        
        // ==========================================
        // 【实装优化】：在 +load 时集中初始化，彻底消灭每帧的 Runtime 检索开销
        g_touchClass = [UITouch class];
        g_ivarView = class_getInstanceVariable(g_touchClass, "_view");
        g_ivarLocation = class_getInstanceVariable(g_touchClass, "_locationInWindow");
        g_ivarPrevLocation = class_getInstanceVariable(g_touchClass, "_previousLocationInWindow");
        // ==========================================
    });
}

- (void)ut_sendEvent:(UIEvent *)event
{


    // 1. 让系统和 WebView 先走正常响应
    [self ut_sendEvent:event];
    if (![[H5View shared] GetThrough]) {
             return;
        }
    if (event.type != UIEventTypeTouches)
        return;

    UIView *unityView = UnityGetGLView();
    if (!unityView)
        return;

    NSSet *touches = event.allTouches;
    UITouch *touch = [touches anyObject];
    if (!touch)
        return;

    // 2. 拦截所有来自 WebView 或非 UnityView 的点击
    if (touch.view != unityView && ![touch.view isDescendantOfView:unityView]) {
        
        UITouchPhase phase = touch.phase;
        
        if (phase == UITouchPhaseMoved) {
            CFTimeInterval currentTime = CACurrentMediaTime();
            if (currentTime - g_lastMovedTime < 0.016) {
                return;
            }
            g_lastMovedTime = currentTime;
        }
        
        // 【优化成果】：直接使用 self 获取 keyWindow
        UIWindow *window = self.keyWindow;
        if (!window && unityView.window) {
            window = unityView.window;
        }
        
        // ==========================================
        // 【实装优化】：window == nil 时提前返回，防止后续无意义计算与 KVC 崩溃风险
        if (!window) {
            return;
        }
        // ==========================================
        
        // 【优化成果】：提取 locationInView 只计算一次
        CGPoint pointInWindow = [touch locationInView:window];
        CGPoint pointPrevWindow = [touch previousLocationInView:window];
        
        CGPoint originalLocationStruct = pointInWindow;
        CGPoint originalPrevLocationStruct = pointPrevWindow;
        
        // 【优化成果】：砍掉 convertPoint:fromView: 的矩阵计算
        CGPoint pointInUnity = pointInWindow;
        CGRect unityFrame = unityView.frame;
        if (unityFrame.origin.x != 0 || unityFrame.origin.y != 0) {
            pointInUnity.x -= unityFrame.origin.x;
            pointInUnity.y -= unityFrame.origin.y;
        }
        
        // 【优化安全加固】：保留最后一道防线，防御极端情况下的 NaN / Inf
        if (isnan(pointInUnity.x) || isinf(pointInUnity.x)) pointInUnity.x = 0;
        if (isnan(pointInUnity.y) || isinf(pointInUnity.y)) pointInUnity.y = 0;
        
        // 【优化成果】：在栈上缓存一次 bounds 结构体
        CGRect bounds = unityView.bounds;
        CGFloat viewWidth = bounds.size.width <= 0 ? 375 : bounds.size.width;
        CGFloat viewHeight = bounds.size.height <= 0 ? 812 : bounds.size.height;
        
        // 【优化成果】：改用利于 CPU 分支预测的 if-else 约束范围
        if (pointInUnity.x < 0) {
            pointInUnity.x = 0;
        } else if (pointInUnity.x > viewWidth) {
            pointInUnity.x = viewWidth;
        }
        
        if (pointInUnity.y < 0) {
            pointInUnity.y = 0;
        } else if (pointInUnity.y > viewHeight) {
            pointInUnity.y = viewHeight;
        }

        CGPoint finalInjectPoint = pointInUnity;
        
        // 3. 备份原始值（后续无需重复获取 Ivar，直接使用静态全局变量）
        UIView *originalView = touch.view;
        NSValue *originalLocation = nil;
        NSValue *originalPrevLocation = nil;
        
        if (g_ivarLocation) {
            originalLocation = [touch valueForKey:@"locationInWindow"];
        }
        if (g_ivarPrevLocation) {
            originalPrevLocation = [touch valueForKey:@"previousLocationInWindow"];
        }

        // 4. 【强制临时修改】重写原生 touch
        if (g_ivarView) {
            object_setIvar(touch, g_ivarView, unityView);
        } else {
            [touch setValue:unityView forKey:@"view"];
        }

        if (g_ivarLocation) object_setIvar(touch, g_ivarLocation, [NSValue valueWithCGPoint:finalInjectPoint]);
        
        // 计算 Moved 阶段的伪造历史坐标
        if (phase == UITouchPhaseMoved && originalLocation && originalPrevLocation) {
            CGPoint offset = CGPointMake(originalLocationStruct.x - originalPrevLocationStruct.x, originalLocationStruct.y - originalPrevLocationStruct.y);
            CGPoint fakePrevPoint = CGPointMake(finalInjectPoint.x - offset.x, finalInjectPoint.y - offset.y);
            
            if (isnan(fakePrevPoint.x) || isinf(fakePrevPoint.x)) fakePrevPoint.x = finalInjectPoint.x;
            if (isnan(fakePrevPoint.y) || isinf(fakePrevPoint.y)) fakePrevPoint.y = finalInjectPoint.y;
            
            if (fakePrevPoint.x < 0) {
                fakePrevPoint.x = 0;
            } else if (fakePrevPoint.x > viewWidth) {
                fakePrevPoint.x = viewWidth;
            }
            
            if (fakePrevPoint.y < 0) {
                fakePrevPoint.y = 0;
            } else if (fakePrevPoint.y > viewHeight) {
                fakePrevPoint.y = viewHeight;
            }
            
            if (g_ivarPrevLocation) object_setIvar(touch, g_ivarPrevLocation, [NSValue valueWithCGPoint:fakePrevPoint]);
        } else {
            if (g_ivarPrevLocation) object_setIvar(touch, g_ivarPrevLocation, [NSValue valueWithCGPoint:finalInjectPoint]);
        }
        
        [touch setValue:[NSValue valueWithCGPoint:finalInjectPoint] forKey:@"locationInWindow"];

        // 5. 将清洗干净的事件丢给 UnityView 通道
        switch (phase) {
            case UITouchPhaseBegan:     [unityView touchesBegan:touches withEvent:event]; break;
            case UITouchPhaseMoved:     [unityView touchesMoved:touches withEvent:event]; break;
            case UITouchPhaseEnded:     [unityView touchesEnded:touches withEvent:event]; break;
            case UITouchPhaseCancelled: [unityView touchesCancelled:touches withEvent:event]; break;
            default: break;
        }

        // 6. 立刻恢复现场
        if (g_ivarView) {
            object_setIvar(touch, g_ivarView, originalView);
        } else {
            [touch setValue:originalView forKey:@"view"];
        }
        
        if (g_ivarLocation && originalLocation) {
            object_setIvar(touch, g_ivarLocation, originalLocation);
            [touch setValue:originalLocation forKey:@"locationInWindow"];
        }
        if (g_ivarPrevLocation && originalPrevLocation) {
            object_setIvar(touch, g_ivarPrevLocation, originalPrevLocation);
        }
    }
}

@end
