// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;
import 'dart:math';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

typedef Painter = void Function(Canvas canvas, Rect rect);

typedef LatticeTapCallback = void Function(Offset? offset);

/// A cell in a [LatticeScrollView].
@immutable
class LatticeCell extends _LatticeCell {
  const LatticeCell({
    super.painter,
    this.builder,
    super.onTap,
    this.taskName,
  });

  final WidgetBuilder? builder;

  final String? taskName;

  @override
  bool get hasChild => builder != null;
}

/// A bidirectional scrollable view that draws arrays of arrays of [LatticeCell]s.
///
/// Only the [cells] that are visible are drawn.
///
/// The cells will be sized according to [cellSize].
class LatticeScrollView extends StatelessWidget {
  const LatticeScrollView({
    super.key,
    this.horizontalPhysics,
    this.horizontalController,
    this.textDirection,
    this.verticalPhysics,
    this.verticalController,
    this.dragStartBehavior = DragStartBehavior.start,
    required this.cells,
    required this.cellSize,
  });

  final ScrollPhysics? horizontalPhysics;

  final ScrollController? horizontalController;

  final TextDirection? textDirection;

  final ScrollPhysics? verticalPhysics;

  final ScrollController? verticalController;

  final DragStartBehavior dragStartBehavior;

  final List<List<LatticeCell>> cells;

  final Size cellSize;

  @override
  Widget build(BuildContext context) {
    final TextDirection textDirection = this.textDirection ?? Directionality.of(context);
    return Scrollbar(
      controller: horizontalController,
      thumbVisibility: true,
      child: Scrollable(
        dragStartBehavior: dragStartBehavior,
        axisDirection: textDirectionToAxisDirection(textDirection),
        controller: horizontalController,
        physics: horizontalPhysics,
        scrollBehavior: _MouseDragScrollBehavior.instance,
        viewportBuilder: (BuildContext context, ViewportOffset horizontalOffset) =>
            NotificationListener<OverscrollNotification>(
          onNotification: (notification) =>
              notification.metrics.axisDirection != AxisDirection.right &&
              notification.metrics.axisDirection != AxisDirection.left,
          child: _FakeViewport(
            child: Scrollbar(
              thumbVisibility: true,
              controller: verticalController,
              child: Scrollable(
                dragStartBehavior: dragStartBehavior,
                axisDirection: AxisDirection.down,
                controller: verticalController,
                physics: verticalPhysics,
                scrollBehavior: _MouseDragScrollBehavior.instance,
                viewportBuilder: (BuildContext context, ViewportOffset verticalOffset) => _FakeViewport(
                  child: _LatticeBody(
                    textDirection: textDirection,
                    horizontalOffset: horizontalOffset,
                    verticalOffset: verticalOffset,
                    cells: cells,
                    cellSize: cellSize,
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _FakeViewport extends SingleChildRenderObjectWidget {
  const _FakeViewport({
    super.child,
  });

  @override
  _RenderFakeViewport createRenderObject(BuildContext context) => _RenderFakeViewport();
}

class _RenderFakeViewport extends RenderProxyBox implements RenderAbstractViewport {
  _RenderFakeViewport({
    RenderBox? child,
  }) : super(child);

  @override
  RevealedOffset getOffsetToReveal(RenderObject target, double alignment, {Rect? rect}) {
    // TODO(ianh): Implement this for real (and make these not be "Fake")
    return RevealedOffset(offset: 0.0, rect: rect ?? target.paintBounds);
  }
}

/// Used to mark classes that would be made public if the rendering object side
/// of this contraption is ever made public.
const Object _public = Object();

@_public
class _LatticeBody extends RenderObjectWidget {
  const _LatticeBody({
    required this.textDirection,
    required this.horizontalOffset,
    required this.verticalOffset,
    required this.cells,
    required this.cellSize,
  });

  final TextDirection textDirection;
  final ViewportOffset horizontalOffset;
  final ViewportOffset verticalOffset;
  final List<List<LatticeCell>> cells;
  final Size cellSize;

  @override
  _RenderLatticeBody createRenderObject(BuildContext context) {
    return _RenderLatticeBody(
      textDirection: textDirection,
      horizontalOffset: horizontalOffset,
      verticalOffset: verticalOffset,
      cells: cells,
      cellSize: cellSize,
      delegate: context as _LatticeBodyElement,
    );
  }

  @override
  void updateRenderObject(BuildContext context, _RenderLatticeBody renderObject) {
    renderObject
      ..textDirection = textDirection
      ..horizontalOffset = horizontalOffset
      ..verticalOffset = verticalOffset
      ..cells = cells
      ..cellSize = cellSize
      ..delegate = context as _LatticeBodyElement;
  }

  @override
  RenderObjectElement createElement() => _LatticeBodyElement(this);
}

@_public
class _LatticeBodyElement extends RenderObjectElement implements _LatticeDelegate {
  _LatticeBodyElement(_LatticeBody super.widget);

  @override
  _LatticeBody get widget => super.widget as _LatticeBody;

  @override
  _RenderLatticeBody get renderObject => super.renderObject as _RenderLatticeBody;

  // This element uses _Coordinate objects as slots.

  Map<Key?, Element?> _newChildrenByKey = <Key?, Element?>{};
  Map<Key?, Element?>? _oldChildrenByKey;
  Map<_Coordinate, Element?> _newChildrenByCoordinate = <_Coordinate, Element?>{};
  Map<_Coordinate, Element?>? _oldChildrenByCoordinate;

  @override
  void beginLayout() {
    _oldChildrenByKey = _newChildrenByKey;
    _newChildrenByKey = <Key?, Element?>{};
    _oldChildrenByCoordinate = _newChildrenByCoordinate;
    _newChildrenByCoordinate = <_Coordinate, Element?>{};
  }

  @override
  RenderBox? updateLatticeChild(_Coordinate coordinate, LatticeCell cell, RenderBox? oldChild) {
    Widget? newWidget;
    Element? newElement;
    owner!.buildScope(this, () {
      try {
        newWidget = cell.builder!(this);
        debugWidgetBuilderValue(widget, newWidget);
      } catch (exception, stack) {
        newWidget = ErrorWidget.builder(
          _debugReportException(
            FlutterErrorDetails(
              context: ErrorDescription('building cell $coordinate for $widget'),
              exception: exception,
              stack: stack,
              library: 'Flutter Dashboard',
              informationCollector: () sync* {
                yield DiagnosticsDebugCreator(DebugCreator(this));
              },
            ),
          ),
        );
      }
      Element? oldElement;
      if (newWidget!.key != null) {
        oldElement = _oldChildrenByKey![newWidget!.key];
        if (oldElement != null) {
          _oldChildrenByKey![newWidget!.key] = null; // null indicates it exists but is not in the grid
          _oldChildrenByCoordinate!.remove(oldElement.slot as _Coordinate?);
        }
      } else {
        oldElement = _oldChildrenByCoordinate![coordinate];
        if (oldElement != null && oldElement.widget.key != null) {
          oldElement = null;
        }
        _oldChildrenByCoordinate!.remove(coordinate);
      }
      try {
        newElement = updateChild(oldElement, newWidget, coordinate);
      } catch (e, stack) {
        newWidget = ErrorWidget.builder(
          _debugReportException(
            FlutterErrorDetails(
              context: ErrorDescription('building widget $newWidget at cell $coordinate for $widget'),
              exception: e,
              stack: stack,
              library: 'Flutter Dashboard',
              informationCollector: () sync* {
                yield DiagnosticsDebugCreator(DebugCreator(this));
              },
            ),
          ),
        );
        newElement = updateChild(null, newWidget, slot);
      }
    });
    assert(newElement!.slot == coordinate);
    if (newWidget!.key != null) {
      _newChildrenByKey[newWidget!.key] = newElement;
    }
    _newChildrenByCoordinate[coordinate] = newElement;
    return newElement!.renderObject as RenderBox?;
  }

  @override
  void endLayout() {
    for (final Element? oldChild in _oldChildrenByCoordinate!.values) {
      if (oldChild!.widget.key == null) {
        updateChild(oldChild, null, null);
      }
    }
    for (final Element? oldChild in _oldChildrenByKey!.values) {
      updateChild(oldChild, null, null);
    }
    _oldChildrenByKey = null;
    _oldChildrenByCoordinate = null;
  }

  @override
  void forgetChild(Element child) {
    if (child.widget.key != null) {
      _newChildrenByKey.remove(child.widget.key);
    }
    _newChildrenByCoordinate.remove(child.slot as _Coordinate?);
    super.forgetChild(child);
  }

  @override
  void insertRenderObjectChild(RenderObject child, _Coordinate? slot) {
    renderObject.placeChild(null, slot, null, child as RenderBox);
  }

  @override
  void moveRenderObjectChild(RenderObject child, _Coordinate? oldSlot, _Coordinate? newSlot) {
    renderObject.placeChild(oldSlot, newSlot, child as RenderBox?, child as RenderBox);
  }

  @override
  void removeRenderObjectChild(RenderObject child, _Coordinate? slot) {
    renderObject.removeChild(slot, child as RenderBox);
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    (_newChildrenByCoordinate.values.whereType<Element>().toList()..sort(_compareChildren)).forEach(visitor);
  }

  int _compareChildren(Element a, Element b) {
    final _Coordinate aSlot = a.slot as _Coordinate;
    final _Coordinate bSlot = b.slot as _Coordinate;
    return aSlot.compareTo(bSlot);
  }

  @override
  List<DiagnosticsNode> debugDescribeChildren() {
    final List<Element> children = _newChildrenByCoordinate.values.whereType<Element>().toList()
      ..sort(_compareChildren);
    return children.map((Element? child) {
      return child!.toDiagnosticsNode(name: child.slot != null ? '${child.slot}' : '(lost)');
    }).toList();
  }
}

@immutable
@_public
class _Coordinate implements Comparable<_Coordinate> {
  const _Coordinate(this.x, this.y);

  final int x;

  final int y;

  @override
  int compareTo(_Coordinate other) {
    if (y == other.y) {
      return x - other.x;
    }
    return y - other.y;
  }

  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType) {
      return false;
    }
    return other is _Coordinate && other.x == x && other.y == y;
  }

  @override
  int get hashCode => Object.hash(x, y);

  @override
  String toString() => '($x,$y)';

  Offset asOffset(Size cellSize) => Offset(x.toDouble() * cellSize.width, y.toDouble() * cellSize.height);
}

@_public
class _LatticeParentData extends ParentData {
  _Coordinate? coordinate;
}

@immutable
@_public
class _LatticeCell {
  const _LatticeCell({
    this.painter,
    this.onTap,
  });

  static const _LatticeCell empty = _LatticeCell();

  final Painter? painter;

  final LatticeTapCallback? onTap;

  @protected
  bool get hasChild => false;
}

@_public
abstract class _LatticeDelegate {
  const _LatticeDelegate();
  void beginLayout();
  RenderBox? updateLatticeChild(_Coordinate coordinate, covariant _LatticeCell cell, RenderBox? oldChild);
  void endLayout();
}

@_public
class _RenderLatticeBody extends RenderBox {
  _RenderLatticeBody({
    required TextDirection textDirection,
    required ViewportOffset horizontalOffset,
    required ViewportOffset verticalOffset,
    required List<List<_LatticeCell>> cells,
    required Size cellSize,
    required _LatticeDelegate delegate,
  })  : assert(!cellSize.isEmpty),
        _textDirection = textDirection,
        _horizontalOffset = horizontalOffset,
        _verticalOffset = verticalOffset,
        _cells = cells,
        _cellSize = cellSize,
        _delegate = delegate {
    _handleOffsetChange();
    _recomputeCellDimensions();
  }

  TextDirection get textDirection => _textDirection;
  TextDirection _textDirection;
  set textDirection(TextDirection value) {
    if (value == _textDirection) {
      return;
    }
    _textDirection = value;
    markNeedsPaint();
  }

  ViewportOffset get horizontalOffset => _horizontalOffset;
  ViewportOffset _horizontalOffset;
  set horizontalOffset(ViewportOffset value) {
    if (value == _horizontalOffset) {
      return;
    }
    if (attached) {
      _horizontalOffset.removeListener(_handleOffsetChange);
    }
    _horizontalOffset = value;
    if (attached) {
      _horizontalOffset.addListener(_handleOffsetChange);
    }
    _handleOffsetChange();
  }

  ViewportOffset get verticalOffset => _verticalOffset;
  ViewportOffset _verticalOffset;
  set verticalOffset(ViewportOffset value) {
    if (value == _verticalOffset) {
      return;
    }
    if (attached) {
      _verticalOffset.removeListener(_handleOffsetChange);
    }
    _verticalOffset = value;
    if (attached) {
      _verticalOffset.addListener(_handleOffsetChange);
    }
    _handleOffsetChange();
  }

  int _cellWidthCount = 0, _cellHeightCount = 0;

  List<List<_LatticeCell>> get cells => _cells;
  List<List<_LatticeCell>> _cells;
  set cells(List<List<_LatticeCell>> value) {
    if (value == _cells) {
      return;
    }
    _cells = value;
    markNeedsLayout();
    _recomputeCellDimensions();
  }

  void _recomputeCellDimensions() {
    _cellWidthCount = cells.fold<int>(0, (int current, List<_LatticeCell> row) => math.max(current, row.length));
    _cellHeightCount = cells.length;
    _handleOffsetChange();
  }

  Size get cellSize => _cellSize;
  Size _cellSize;
  set cellSize(Size value) {
    assert(!value.isEmpty);
    if (value == _cellSize) {
      return;
    }
    _cellSize = value;
    markNeedsLayout();
  }

  _LatticeDelegate get delegate => _delegate;
  _LatticeDelegate _delegate;
  set delegate(_LatticeDelegate value) {
    if (value == _delegate) {
      return;
    }
    _delegate = value;
    markNeedsLayout();
  }

  // TODO(ianh): rather than store and paint the children directly in
  // this render object, dynamically create _RenderLatticeTiles that
  // handle cacheStride x cacheStride sections of the grid. This would
  // give us more efficient scrolling since we would not need to
  // update them. We would need to make sure to mark them all as
  // needing layout when the list of widgets changed.
  //
  // Currently, we have to repaint everything when we scroll because
  // we have no way to cache the paint in a layer.

  _LatticeCell? _getCellFor(_Coordinate coordinate) {
    if (coordinate.y < 0 || coordinate.x < 0) {
      return null;
    }
    if (coordinate.y >= cells.length) {
      return null;
    }
    if (coordinate.x >= cells[coordinate.y].length) {
      return null;
    }
    return cells[coordinate.y][coordinate.x];
  }

  bool _hasTapHandler(_Coordinate coordinate) {
    return _getCellFor(coordinate)?.onTap != null;
  }

  final Map<_Coordinate?, RenderBox> _childrenByCoordinate = <_Coordinate?, RenderBox>{};

  void placeChild(_Coordinate? oldCoordinate, _Coordinate? newCoordinate, RenderBox? oldChild, RenderBox newChild) {
    if (oldChild == newChild) {
      return;
    }
    if (oldChild != null) {
      final _LatticeParentData oldChildParentData = oldChild.parentData as _LatticeParentData;
      oldChildParentData.coordinate = null;
    }
    if (oldCoordinate != null) {
      _childrenByCoordinate.remove(oldCoordinate);
    }
    _childrenByCoordinate[newCoordinate] = newChild;
    if (newChild.parent != this) {
      adoptChild(newChild);
    }
    final _LatticeParentData newChildParentData = newChild.parentData as _LatticeParentData;
    newChildParentData.coordinate = newCoordinate;
  }

  void removeChild(_Coordinate? coordinate, RenderBox child) {
    if (coordinate != null) {
      _childrenByCoordinate.remove(coordinate);
    }
    dropChild(child);
  }

  @override
  void setupParentData(RenderObject child) {
    if (child.parentData is! ParentData) {
      child.parentData = _LatticeParentData();
    }
  }

  TapGestureRecognizer? _tap;

  @override
  void attach(PipelineOwner owner) {
    super.attach(owner);
    _horizontalOffset.addListener(_handleOffsetChange);
    _verticalOffset.addListener(_handleOffsetChange);
    _tap = TapGestureRecognizer(debugOwner: this)
      ..onTapDown = _handleTapDown
      ..onTapUp = _handleTapUp;
    for (final RenderBox child in _childrenByCoordinate.values) {
      child.attach(owner);
    }
  }

  @override
  void detach() {
    super.detach();
    _horizontalOffset.removeListener(_handleOffsetChange);
    _verticalOffset.removeListener(_handleOffsetChange);
    _tap?.dispose();
    for (final RenderBox child in _childrenByCoordinate.values) {
      child.detach();
    }
  }

  @override
  void dispose() {
    super.dispose();
    _clipLabelColumnHandle.layer = null;
    _clipLabelRowHandle.layer = null;
    _clipDataHandle.layer = null;
  }

  @override
  void redepthChildren() {
    _childrenByCoordinate.values.forEach(redepthChild);
  }

  @override
  void visitChildren(RenderObjectVisitor visitor) {
    _childrenByCoordinate.values.forEach(visitor);
  }

  @override
  bool get isRepaintBoundary => true;

  @override
  double computeMinIntrinsicWidth(double? height) {
    return _cellWidthCount * cellSize.width;
  }

  @override
  double computeMaxIntrinsicWidth(double height) {
    return computeMinIntrinsicWidth(height);
  }

  @override
  double computeMinIntrinsicHeight(double? width) {
    return _cellHeightCount * cellSize.height;
  }

  @override
  double computeMaxIntrinsicHeight(double width) {
    return computeMinIntrinsicHeight(width);
  }

  @override
  bool get sizedByParent => true;

  @override
  void performResize() {
    size = Size(
      constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(computeMinIntrinsicWidth(null)),
      constraints.hasBoundedHeight
          ? constraints.maxHeight
          : constraints.constrainHeight(computeMinIntrinsicHeight(null)),
    );
    horizontalOffset.applyViewportDimension(size.width);
    verticalOffset.applyViewportDimension(size.height);
    _handleOffsetChange(duringLayout: true);
  }

  Offset? _scrollOffset;
  int? _firstX, _firstY, _lastX, _lastY;

  void _handleOffsetChange({bool duringLayout = false}) {
    if (!hasSize) {
      assert(_scrollOffset == null);
      return;
    }
    final Offset scrollOffset = Offset(horizontalOffset.pixels, verticalOffset.pixels);
    final int firstX = scrollOffset.dx ~/ cellSize.width;
    final int lastX = ((scrollOffset.dx + size.width) / cellSize.width).ceil() - 1;
    final int firstY = scrollOffset.dy ~/ cellSize.height;
    final int lastY = math.min(((scrollOffset.dy + size.height) / cellSize.height).ceil(), _cellHeightCount) - 1;
    if (scrollOffset != _scrollOffset) {
      _scrollOffset = scrollOffset;
      markNeedsPaint();
    }
    if (firstX != _firstX || lastX != _lastX || firstY != _firstY || lastY != _lastY) {
      _firstX = firstX;
      _lastX = lastX;
      _firstY = firstY;
      _lastY = lastY;
      if (!duringLayout) {
        markNeedsLayout();
      }
    }
  }

  @override
  void performLayout() {
    assert(_scrollOffset != null);
    final BoxConstraints childConstraints = BoxConstraints.tight(cellSize);
    invokeLayoutCallback<BoxConstraints>((BoxConstraints constraints) {
      delegate.beginLayout();
    });
    for (int y = 0; y < _cellHeightCount; y += 1) {
      for (int x = 0; x < _cellWidthCount; x += 1) {
        final _Coordinate here = _Coordinate(x, y);
        final bool visible = (x == 0 || x >= _firstX!) && x <= _lastX! && (y == 0 || y >= _firstY!) && y <= _lastY!;
        assert(y < cells.length);
        final _LatticeCell cell = x < cells[y].length ? cells[y][x] : _LatticeCell.empty;
        if (visible && cell.hasChild) {
          RenderBox? child;
          invokeLayoutCallback<BoxConstraints>((BoxConstraints constraints) {
            child = delegate.updateLatticeChild(here, cell, _childrenByCoordinate[here]);
          });
          assert(child != null);
          assert(child!.parent == this);
          assert(_childrenByCoordinate[here] == child);
          child!.layout(childConstraints);
        }
      }
    }
    invokeLayoutCallback<BoxConstraints>((BoxConstraints constraints) {
      delegate.endLayout();
    });
    horizontalOffset.applyContentDimensions(
      0.0,
      math.max(0.0, computeMinIntrinsicWidth(null) - size.width),
    );
    verticalOffset.applyContentDimensions(
      0.0,
      math.max(0.0, computeMinIntrinsicHeight(null) - size.height),
    );
  }

  final LayerHandle<ClipRectLayer> _clipLabelRowHandle = LayerHandle<ClipRectLayer>();
  final LayerHandle<ClipRectLayer> _clipLabelColumnHandle = LayerHandle<ClipRectLayer>();
  final LayerHandle<ClipRectLayer> _clipDataHandle = LayerHandle<ClipRectLayer>();

  void _paintCell(PaintingContext context, Offset offset, int x, int y) {
    final _Coordinate here = _Coordinate(x, y);
    assert(y < cells.length);
    final _LatticeCell cell = x < cells[y].length ? cells[y][x] : _LatticeCell.empty;
    final Offset topLeft = _coordinateToOffset(here)! + offset;
    final Painter? painter = cell.painter;
    final RenderBox? child = cell.hasChild ? _childrenByCoordinate[here] : null;
    assert(child == _childrenByCoordinate[here]);
    assert(cell.hasChild == (child != null));
    if (painter != null) {
      painter(context.canvas, topLeft & cellSize);
    }
    if (child != null) {
      context.paintChild(child, topLeft);
    }
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    assert(needsCompositing);
    final Offset dataOffset = Offset(cellSize.width, cellSize.height);
    final Size dataSize = size - dataOffset as Size;
    if (dataSize.isEmpty) {
      return;
    }
    _clipLabelColumnHandle.layer = context.pushClipRect(
      needsCompositing,
      offset,
      Rect.fromLTWH(0, dataOffset.dy, cellSize.width, dataSize.height),
      (PaintingContext context, Offset offset) {
        for (int y = max(1, _firstY!); y <= _lastY!; y += 1) {
          _paintCell(context, offset, 0, y);
        }
      },
      oldLayer: _clipLabelColumnHandle.layer,
    );
    _clipLabelRowHandle.layer = context.pushClipRect(
      needsCompositing,
      offset,
      Rect.fromLTWH(dataOffset.dx, 0, dataSize.width, cellSize.height),
      (PaintingContext context, Offset offset) {
        for (int x = max(1, _firstX!); x <= _lastX!; x += 1) {
          _paintCell(context, offset, x, 0);
        }
      },
      oldLayer: _clipLabelRowHandle.layer,
    );
    _clipDataHandle.layer = context.pushClipRect(
      needsCompositing,
      offset,
      dataOffset & dataSize,
      (PaintingContext context, Offset offset) {
        for (int y = _firstY! + 1; y <= _lastY!; y += 1) {
          for (int x = _firstX! + 1; x <= _lastX!; x += 1) {
            _paintCell(context, offset, x, y);
          }
        }
      },
      oldLayer: _clipDataHandle.layer,
    );
  }

  @override
  void applyPaintTransform(RenderBox child, Matrix4 transform) {
    final _LatticeParentData childParentData = child.parentData as _LatticeParentData;
    final Offset offset = _coordinateToOffset(childParentData.coordinate!)!;
    transform.translate(offset.dx, offset.dy);
  }

  @override
  Rect describeApproximatePaintClip(RenderObject child) => Offset.zero & size;

  @override
  void showOnScreen({
    RenderObject? descendant,
    Rect? rect,
    Duration duration = Duration.zero,
    Curve curve = Curves.ease,
  }) {
    if (descendant != null) {
      // TODO(ianh): Implement this. Not having this implemented means
      // accessibility scrolling won't work for this viewport.
      //
      // The implementation should honor allowImplicitScrolling on
      // horizontalOffset and verticalOffset, descendant and rect, and
      // duration and curve. (If duration is Duration.zero, use jumpTo
      // on the offsets, otherwise use animateTo.)
    }
    super.showOnScreen(
      rect: rect,
      duration: duration,
      curve: curve,
    );
  }

  _Coordinate? _offsetToCoordinate(Offset? position) {
    late Offset absolute;
    switch (textDirection) {
      case TextDirection.rtl:
        absolute = Offset(position!.dx - _scrollOffset!.dx, position.dy + _scrollOffset!.dy);
        break;
      case TextDirection.ltr:
        absolute = position! + _scrollOffset!;
        break;
    }
    switch (textDirection) {
      case TextDirection.rtl:
        return _Coordinate(
          position.dx + cellSize.width > size.width ? 0 : (size.width - absolute.dx) ~/ cellSize.width,
          position.dy < cellSize.height ? 0 : absolute.dy ~/ cellSize.height,
        );
      case TextDirection.ltr:
        return _Coordinate(
          position.dx < cellSize.width ? 0 : absolute.dx ~/ cellSize.width,
          position.dy < cellSize.height ? 0 : absolute.dy ~/ cellSize.height,
        );
    }
  }

  Offset? _coordinateToOffset(_Coordinate coordinate) {
    final Offset adjustedScroll = Offset(
      coordinate.x == 0 ? 0 : _scrollOffset!.dx,
      coordinate.y == 0 ? 0 : _scrollOffset!.dy,
    );
    switch (textDirection) {
      case TextDirection.rtl:
        return Offset(
          size.width - (coordinate.x * cellSize.width) - cellSize.width + adjustedScroll.dx,
          coordinate.y * cellSize.height - adjustedScroll.dy,
        );
      case TextDirection.ltr:
        return Offset(
              coordinate.x * cellSize.width,
              coordinate.y * cellSize.height,
            ) -
            adjustedScroll;
    }
  }

  @override
  bool hitTestChildren(BoxHitTestResult result, {Offset? position}) {
    final _Coordinate? coordinate = _offsetToCoordinate(position);
    final RenderBox? child = _childrenByCoordinate[coordinate];
    return child != null &&
        result.addWithPaintOffset(
          offset: _coordinateToOffset(coordinate!),
          position: position!,
          hitTest: (BoxHitTestResult result, Offset transformed) {
            return child.hitTest(result, position: transformed);
          },
        );
  }

  @override
  bool hitTestSelf(Offset position) => true;

  @override
  void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
    assert(debugHandleEvent(event, entry));
    final _Coordinate? coordinate = _offsetToCoordinate(event.localPosition);
    if (event is PointerDownEvent && _hasTapHandler(coordinate!)) {
      _tap?.addPointer(event);
    }
  }

  _Coordinate? _lastTapDown;

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

  void _handleTapUp(TapUpDetails details) {
    final _Coordinate? lastTapUp = _offsetToCoordinate(details.localPosition);
    if (_lastTapDown == lastTapUp && _hasTapHandler(lastTapUp!)) {
      _getCellFor(_lastTapDown!)!.onTap!(_coordinateToOffset(lastTapUp));
    }
  }

  @override
  Rect describeSemanticsClip(RenderObject? child) => (Offset.zero & size).inflate(cellSize.longestSide);
}

FlutterErrorDetails _debugReportException(FlutterErrorDetails details) {
  FlutterError.reportError(details);
  return details;
}

/// A [MaterialScrollBehavior] that supports mouse dragging.
class _MouseDragScrollBehavior extends MaterialScrollBehavior {
  static _MouseDragScrollBehavior? _instance;
  static _MouseDragScrollBehavior get instance => _instance ??= _MouseDragScrollBehavior();

  @override
  Set<PointerDeviceKind> get dragDevices => <PointerDeviceKind>{
        PointerDeviceKind.touch,
        PointerDeviceKind.mouse,
      };
}
