import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

class ResponsivePair extends StatefulWidget {
  final List<Widget> children;
  final MainAxisAlignment rowMainAxisAlignment;
  final CrossAxisAlignment rowCrossAxisAlignment;

  final MainAxisAlignment colMainAxisAlignment;
  final CrossAxisAlignment colCrossAxisAlignment;

  const ResponsivePair({
    super.key,
    required this.children,
    this.rowMainAxisAlignment = MainAxisAlignment.spaceBetween,
    this.rowCrossAxisAlignment = CrossAxisAlignment.center,
    this.colMainAxisAlignment = MainAxisAlignment.spaceBetween,
    this.colCrossAxisAlignment = CrossAxisAlignment.start,
  });

  @override
  State<StatefulWidget> createState() => _ResponsivePairState();
}

class _ResponsivePairState extends State<ResponsivePair> {
  var _computed = false;
  final Map<int, double> _childWidth = {};
  var _isRow = true;

  @override
  void initState() {
    super.initState();
  }

  void refreshSize() {
    if (_childWidth.length != widget.children.length) return;

    var sum = _childWidth.values.reduce((value, element) => value + element);
    var width = context.size?.width ?? 0;

    setState(() {
      _computed = true;
      _isRow = sum < width;
    });
  }

  void handleSizeChange(Size size, int id) {
    _childWidth[id] = size.width;
    if (_childWidth.length == widget.children.length) {
      refreshSize();
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    setState(() {
      _computed = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    Widget inner;
    if (!_computed) {
      List<Widget> stackChildren = [];
      for (var i = 0; i < widget.children.length; i++) {
        // Only first child is visible
        stackChildren.add(
          Opacity(
            opacity: i == 0 ? 1 : 0,
            child: WidgetSizeOffsetWrapper(
              id: i,
              onSizeChange: handleSizeChange,
              child: widget.children[i],
            ),
          ),
        );
      }
      inner = Stack(
        children: stackChildren,
      );
    } else {
      if (_isRow) {
        var i = -1;
        var children = widget.children.map((child) {
          i++;
          if (i != 0) {
            return Flexible(child: child);
          }
          return child;
        }).toList();
        inner = Row(
          mainAxisAlignment: widget.rowMainAxisAlignment,
          crossAxisAlignment: widget.rowCrossAxisAlignment,
          children: children,
        );
      } else {
        inner = Column(
          mainAxisAlignment: widget.colMainAxisAlignment,
          crossAxisAlignment: widget.colCrossAxisAlignment,
          children: widget.children,
        );
      }
    }
    return AnimatedSize(
      duration: const Duration(milliseconds: 150),
      curve: Curves.linear,
      alignment: Alignment.topCenter,
      child: inner,
    );
  }
}

typedef WidgetSizeChangeCallback = void Function(Size size, int id);

class WidgetSizeRenderObject extends RenderProxyBox {
  final WidgetSizeChangeCallback onSizeChange;
  final int id;
  Size? currentSize;

  WidgetSizeRenderObject(this.onSizeChange, this.id);

  @override
  void performLayout() {
    super.performLayout();

    try {
      Size? newSize = child?.size;

      if (newSize != null && currentSize != newSize) {
        currentSize = newSize;
        WidgetsBinding.instance.addPostFrameCallback((_) {
          onSizeChange(newSize, id);
        });
      }
    } catch (e, stack) {
      debugPrint("$e $stack");
    }
  }
}

class WidgetSizeOffsetWrapper extends SingleChildRenderObjectWidget {
  final WidgetSizeChangeCallback onSizeChange;
  final int id;

  const WidgetSizeOffsetWrapper({
    Key? key,
    required this.onSizeChange,
    required this.id,
    required Widget child,
  }) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return WidgetSizeRenderObject(onSizeChange, id);
  }
}