part of '../async_action_button.dart';

class _AsyncMixin extends StatefulWidget {
  final AsyncActionCallback? onPressed;
  final AsyncActionController? controller;
  final AsyncErrorBuilder? errorBuilder;
  final void Function(String message)? onError;
  final VoidCallback? onSuccess;
  final Widget Function(BuildContext context, bool busy, VoidCallback? handler)
  builder;

  const _AsyncMixin({
    required this.onPressed,
    required this.builder,
    this.controller,
    this.errorBuilder,
    this.onError,
    this.onSuccess,
  });

  @override
  State<_AsyncMixin> createState() => _AsyncMixinState();
}

class _AsyncMixinState extends State<_AsyncMixin> {
  late final AsyncActionController _internal;
  AsyncActionController get _controller => widget.controller ?? _internal;

  @override
  void initState() {
    super.initState();
    if (widget.controller == null) {
      _internal = AsyncActionController();
    }
    _controller.addListener(_onControllerChange);
  }

  @override
  void didUpdateWidget(covariant _AsyncMixin oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.controller != widget.controller) {
      (oldWidget.controller ?? _internal).removeListener(_onControllerChange);
      _controller.addListener(_onControllerChange);
    }
  }

  @override
  void dispose() {
    _controller.removeListener(_onControllerChange);
    if (widget.controller == null) {
      _internal.dispose();
    }
    super.dispose();
  }

  void _onControllerChange() {
    if (mounted) setState(() {});
  }

  Future<void> _trigger() async {
    final action = widget.onPressed;
    if (action == null) return;
    final success = await _controller.run(
      action,
      errorBuilder: widget.errorBuilder,
    );
    if (!mounted) return;
    if (success) {
      Haptics.success();
      widget.onSuccess?.call();
    } else if (_controller.error != null) {
      Haptics.error();
      widget.onError?.call(_controller.error!);
    }
  }

  @override
  Widget build(BuildContext context) {
    final handler = widget.onPressed == null ? null : _trigger;
    return widget.builder(
      context,
      _controller.busy,
      _controller.busy ? null : handler,
    );
  }
}

class _InlineErrorWrapper extends StatelessWidget {
  final AsyncActionController? controller;
  final Widget child;
  const _InlineErrorWrapper({required this.controller, required this.child});

  @override
  Widget build(BuildContext context) {
    final c = controller;
    if (c == null) return child;
    return AnimatedBuilder(
      animation: c,
      builder: (context, _) {
        final err = c.error;
        return Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            child,
            if (err != null) ...[
              const SizedBox(height: 8),
              Semantics(
                liveRegion: true,
                container: true,
                child: Text(
                  err,
                  textAlign: TextAlign.center,
                  style: _asyncErrorTextStyle(context),
                ),
              ),
            ],
          ],
        );
      },
    );
  }
}
