import 'package:comunic/ui/widgets/safe_state.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';

/// Widget that can be used to easily implement fetch of remote ressources
///
/// @author Pierre Hubert

class AsyncScreenWidget extends StatefulWidget {
  /// Reload function
  ///
  /// Can be an asynchronous function that takes no arguments and throw an
  /// [Exception] in case of failure
  ///
  /// You do not need to call [State.setState] on this function, it is
  /// automatically done by this widget
  final Future<void> Function() onReload;

  /// Build function
  ///
  /// This function will be called whenever [isReady] becomes true
  final Widget Function() onBuild;

  /// Error message that will be shown in case of error
  final String errorMessage;

  const AsyncScreenWidget({
    Key key,
    @required this.onReload,
    @required this.onBuild,
    @required this.errorMessage,
  })  : assert(onReload != null),
        assert(onBuild != null),
        assert(errorMessage != null),
        super(key: key);

  @override
  AsyncScreenWidgetState createState() => AsyncScreenWidgetState();
}

class AsyncScreenWidgetState extends SafeState<AsyncScreenWidget> {
  bool error = false;
  bool ready = false;

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

  @override
  Widget build(BuildContext context) {
    // In case of error
    if (error)
      return buildErrorCard(widget.errorMessage, actions: [
        MaterialButton(
          onPressed: () => refresh(),
          child: Text(tr("Try again").toUpperCase()),
        )
      ]);

    // Show loading states
    if (!ready) return buildCenteredProgressBar();

    // The widget is ready, show it
    return RefreshIndicator(
      child: widget.onBuild(),
      onRefresh: () => refresh(),
    );
  }

  /// Refresh this screen
  Future<void> refresh() async {
    try {
      setState(() {
        error = false;
        ready = false;
      });

      // Call parent method
      await widget.onReload();

      setState(() {
        ready = true;
      });
    } catch (e, stack) {
      print(e);
      print(stack);

      setState(() {
        error = true;
      });
    }
  }
}