import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// 远端触摸控制层（对应 Android 端 RemoteTouchView）。
///
/// 捕获指针（触摸/鼠标）事件，将其转换为相对于控件区域的百分比坐标
/// （0.0 ~ 1.0），以便在不同分辨率的设备间换算。
///
/// - 短时间内位移很小的抬起 -> 单击（TOUCH）
/// - 否则 -> 滑动（SWIPE）
/// - 按住不动超过阈值 -> 长按（LONG_PRESS）
/// 同时捕获物理按键事件（KEY），用于外接键盘 / 遥控器场景。
///
/// 该控件完全基于 Flutter 框架实现，无需任何原生代码，可运行于
/// Android、iOS 等平台。
class RemoteTouchView extends StatefulWidget {
  final void Function(double x, double y) onTouch;
  final void Function(
    double x1,
    double y1,
    double x2,
    double y2,
    int durationMs,
  ) onSwipe;
  final void Function(int keyCode, int action) onKey;
  final void Function(double x, double y) onLongPress;
  final void Function(int action, double x, double y) onMotionEvent;

  const RemoteTouchView({
    super.key,
    required this.onTouch,
    required this.onSwipe,
    required this.onKey,
    required this.onLongPress,
    required this.onMotionEvent,
  });

  @override
  State<RemoteTouchView> createState() => _RemoteTouchViewState();
}

class _RemoteTouchViewState extends State<RemoteTouchView> {
  Offset? _startPosition;
  Offset? _currentPosition;
  DateTime? _startTime;
  bool _isLongPressed = false;
  Timer? _longPressTimer;

  // 缓存 RenderBox 信息以优化坐标换算开销
  RenderBox? _cachedRenderBox;
  Size? _cachedSize;

  // 采样率限制：控制 ACTION_MOVE 的发送频率（例如每 16ms 发送一次，约 60fps）
  int _lastMoveTimestamp = 0;
  static const int _sampleIntervalMs = 16; 

  /// 长按触发阈值，对应 Android GestureDetector 默认的 LONG_PRESS_TIMEOUT（400ms）。
  static const _longPressTimeout = Duration(milliseconds: 400);

  /// 手指移动超过该像素阈值则视为滚动，取消长按（对应 Android touch slop）。
  static const _touchSlop = 10.0;

  double _toRelativeX(Offset local, Size size) =>
      (local.dx / size.width).clamp(0.0, 1.0);

  double _toRelativeY(Offset local, Size size) =>
      (local.dy / size.height).clamp(0.0, 1.0);

  void _cancelLongPress() {
    _longPressTimer?.cancel();
    _longPressTimer = null;
  }

  @override
  void dispose() {
    _cancelLongPress();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Focus(
      autofocus: true,
      onKeyEvent: (node, event) {
        if (event is KeyDownEvent) {
          widget.onKey(event.logicalKey.keyId, 0);
          return KeyEventResult.handled;
        } else if (event is KeyUpEvent) {
          widget.onKey(event.logicalKey.keyId, 1);
          return KeyEventResult.handled;
        }
        return KeyEventResult.ignored;
      },
      child: Listener(
        behavior: HitTestBehavior.opaque,
        onPointerDown: (event) {
          _cancelLongPress();
          _isLongPressed = false;
          _startPosition = event.localPosition;
          _currentPosition = event.localPosition;
          _startTime = DateTime.now();
          _lastMoveTimestamp = 0; // 重置采样计时

          // 开始触摸时缓存 RenderBox 和 Size
          _cachedRenderBox = context.findRenderObject() as RenderBox?;
          _cachedSize = _cachedRenderBox?.size;

          if (_cachedSize != null) {
            final rx = _toRelativeX(event.localPosition, _cachedSize!);
            final ry = _toRelativeY(event.localPosition, _cachedSize!);
            widget.onMotionEvent(0, rx, ry); // ACTION_DOWN
          }

          _longPressTimer = Timer(_longPressTimeout, () {
            if (_currentPosition == null || _cachedSize == null) return;
            _isLongPressed = true;
            final x = _toRelativeX(_currentPosition!, _cachedSize!);
            final y = _toRelativeY(_currentPosition!, _cachedSize!);
            widget.onLongPress(x, y);
          });
        },
        onPointerMove: (event) {
          _currentPosition = event.localPosition;
          
          if (_cachedSize != null) {
            final now = DateTime.now().millisecondsSinceEpoch;
            // 采样率限制逻辑
            if (now - _lastMoveTimestamp >= _sampleIntervalMs) {
              _lastMoveTimestamp = now;
              final rx = _toRelativeX(event.localPosition, _cachedSize!);
              final ry = _toRelativeY(event.localPosition, _cachedSize!);
              widget.onMotionEvent(2, rx, ry); // ACTION_MOVE
            }
          }

          if (_longPressTimer != null && _startPosition != null) {
            if ((event.localPosition - _startPosition!).distance > _touchSlop) {
              _cancelLongPress();
            }
          }
        },
        onPointerUp: (event) {
          _cancelLongPress();

          if (_cachedSize != null) {
            final rx = _toRelativeX(event.localPosition, _cachedSize!);
            final ry = _toRelativeY(event.localPosition, _cachedSize!);
            widget.onMotionEvent(1, rx, ry); // ACTION_UP

            if (!_isLongPressed && _startPosition != null && _startTime != null) {
              final startX = _toRelativeX(_startPosition!, _cachedSize!);
              final startY = _toRelativeY(_startPosition!, _cachedSize!);
              final duration = DateTime.now().difference(_startTime!).inMilliseconds;
              final dx = (rx - startX).abs();
              final dy = (ry - startY).abs();

              if (duration < 200 && dx < 0.02 && dy < 0.02) {
                widget.onTouch(startX, startY);
              } else {
                widget.onSwipe(startX, startY, rx, ry, max(duration, 1));
              }
            }
          }

          // 清理状态
          _startPosition = null;
          _currentPosition = null;
          _startTime = null;
          _cachedRenderBox = null;
          _cachedSize = null;
        },
        child: const ColoredBox(
          color: Colors.transparent,
          child: SizedBox.expand(),
        ),
      ),
    );
  }
}


