import 'dart:async';

import 'package:flutter/material.dart';

import '../../../../core/infra/player_engine/player_engine.dart';

enum _DragMode { none, brightness, volume, seek }

class AndroidGestureLayer extends StatefulWidget {
  const AndroidGestureLayer({
    super.key,
    required this.enabled,
    required this.player,
    required this.onToggleControls,
    required this.onDoubleTapCenter,
    required this.onDoubleTapLeft,
    required this.onDoubleTapRight,
    required this.onBrightnessChange,
    required this.onVolumeChange,
    required this.onVerticalDragEnd,
    required this.onHorizontalSeekUpdate,
    required this.onHorizontalSeekStart,
    required this.onHorizontalSeekEnd,
    required this.onLongPressStart,
    required this.onLongPressEnd,
  });

  final bool enabled;
  final PlayerEngine player;
  final VoidCallback onToggleControls;
  final VoidCallback onDoubleTapCenter;
  final VoidCallback onDoubleTapLeft;
  final VoidCallback onDoubleTapRight;
  final ValueChanged<double> onBrightnessChange;
  final ValueChanged<double> onVolumeChange;
  final VoidCallback onVerticalDragEnd;
  final ValueChanged<Duration> onHorizontalSeekUpdate;
  final VoidCallback onHorizontalSeekStart;
  final VoidCallback onHorizontalSeekEnd;
  final ValueChanged<bool> onLongPressStart;
  final VoidCallback onLongPressEnd;

  @override
  State<AndroidGestureLayer> createState() => _AndroidGestureLayerState();
}

class _AndroidGestureLayerState extends State<AndroidGestureLayer> {
  _DragMode _dragMode = _DragMode.none;
  Offset _panStartPos = Offset.zero;
  double _cumulativeDx = 0;
  double _cumulativeDy = 0;

  Timer? _doubleTapTimer;
  Offset _lastTapDownPos = Offset.zero;

  void _handleTapDown(TapDownDetails details) {
    _lastTapDownPos = details.localPosition;
  }

  void _handleTapUp(TapUpDetails details) {
    final pos = _lastTapDownPos;

    if (_doubleTapTimer != null) {
      _doubleTapTimer!.cancel();
      _doubleTapTimer = null;
      widget.onToggleControls();
      _executeDoubleTap(pos);
    } else {
      widget.onToggleControls();
      _doubleTapTimer = Timer(const Duration(milliseconds: 300), () {
        _doubleTapTimer = null;
      });
    }
  }

  void _executeDoubleTap(Offset pos) {
    final width = context.size?.width ?? 0;
    final third = width / 3;
    if (pos.dx < third) {
      widget.onDoubleTapLeft();
    } else if (pos.dx > third * 2) {
      widget.onDoubleTapRight();
    } else {
      widget.onDoubleTapCenter();
    }
  }

  void _handlePanStart(DragStartDetails details) {
    _panStartPos = details.localPosition;
    _dragMode = _DragMode.none;
    _cumulativeDx = 0;
    _cumulativeDy = 0;
  }

  void _handlePanUpdate(DragUpdateDetails details) {
    _cumulativeDx += details.delta.dx;
    _cumulativeDy += details.delta.dy;

    if (_dragMode == _DragMode.none) {
      final absDx = _cumulativeDx.abs();
      final absDy = _cumulativeDy.abs();
      if (absDx < 20 && absDy < 20) return;

      if (absDx > absDy * 1.5) {
        _dragMode = _DragMode.seek;
        widget.onHorizontalSeekStart();
      } else if (absDy > absDx * 1.5) {
        final screenWidth = context.size?.width ?? 1;
        _dragMode = _panStartPos.dx < screenWidth / 2
            ? _DragMode.brightness
            : _DragMode.volume;
      } else {
        return;
      }
    }

    if (_dragMode == _DragMode.seek) {
      final screenWidth = context.size?.width ?? 1;
      final totalDuration = widget.player.state.duration;
      final seekDelta = totalDuration * (_cumulativeDx / screenWidth) * 0.5;
      widget.onHorizontalSeekUpdate(seekDelta);
    } else if (_dragMode == _DragMode.brightness) {
      final screenHeight = context.size?.height ?? 1;
      final delta = -details.delta.dy / (screenHeight * 0.7);
      widget.onBrightnessChange(delta);
    } else if (_dragMode == _DragMode.volume) {
      final screenHeight = context.size?.height ?? 1;
      final delta = -details.delta.dy / (screenHeight * 1.5);
      widget.onVolumeChange(delta);
    }
  }

  void _handlePanEnd(DragEndDetails details) {
    if (_dragMode == _DragMode.seek) {
      widget.onHorizontalSeekEnd();
    } else if (_dragMode == _DragMode.brightness ||
        _dragMode == _DragMode.volume) {
      widget.onVerticalDragEnd();
    }
    _dragMode = _DragMode.none;
  }

  @override
  void dispose() {
    _doubleTapTimer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!widget.enabled) return const SizedBox.expand();
    return GestureDetector(
      behavior: HitTestBehavior.translucent,
      onTapDown: _handleTapDown,
      onTapUp: _handleTapUp,
      onPanStart: _handlePanStart,
      onPanUpdate: _handlePanUpdate,
      onPanEnd: _handlePanEnd,
      onLongPressStart: (details) {
        final screenWidth = context.size?.width ?? 1;
        final isLeftSide = details.localPosition.dx < screenWidth / 2;
        widget.onLongPressStart(isLeftSide);
      },
      onLongPressEnd: (_) => widget.onLongPressEnd(),
      child: const SizedBox.expand(),
    );
  }
}
