import 'package:comunic/helpers/groups_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/lists/posts_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/post.dart';
import 'package:comunic/ui/screens/conversation_screen.dart';
import 'package:comunic/ui/tiles/post_tile.dart';
import 'package:comunic/ui/widgets/scroll_watcher.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';

/// Posts list widget
///
/// Displays a list of posts
///
/// @author Pierre HUBERT

class PostsListWidget extends StatefulWidget {
  final Future<PostsList> Function() getPostsList;
  final Future<PostsList> Function(int from) getOlder;
  final bool showPostsTarget;
  final bool buildListView;
  final bool userNamesClickable;

  const PostsListWidget({
    Key key,
    @required this.getPostsList,
    @required this.showPostsTarget,
    this.userNamesClickable = true,
    this.buildListView = true,
    this.getOlder,
  })  : assert(getPostsList != null),
        assert(showPostsTarget != null),
        assert(buildListView != null),
        assert(userNamesClickable != null),
        super(key: key);

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

class _PostsListWidgetState extends State<PostsListWidget> {
  // Helpers
  final UsersHelper _usersHelper = UsersHelper();
  final GroupsHelper _groupsHelper = GroupsHelper();

  // Class members
  PostsList _list;
  UsersList _users;
  GroupsList _groups;
  ScrollWatcher _scrollController;
  ErrorLevel _error = ErrorLevel.NONE;
  bool _loading = false;

  set error(ErrorLevel err) => setState(() => _error = err);

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

    _scrollController = ScrollWatcher(onReachBottom: _reachedPostsBottom);
  }

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

  void _loadError() {
    error = _list == null ? ErrorLevel.MAJOR : ErrorLevel.MINOR;
    _loading = false;
  }

  /// Load the list of posts
  Future<void> _loadPostsList({bool getOlder = false}) async {
    if (_loading) return;

    _loading = true;

    final list = !getOlder
        ? await widget.getPostsList()
        : await widget.getOlder(_list.oldestID);

    if (list == null) return _loadError();

    final users = await _usersHelper.getList(list.usersID);

    if (users == null) return _loadError();

    final groups = await _groupsHelper.getList(list.groupsID);

    if (groups == null) return _loadError();

    setState(() {
      if (!getOlder) {
        _list = list;
        _users = users;
        _groups = groups;
      } else {
        _list.addAll(list);
        _users.addAll(users);
        _groups.addAll(groups);
      }
    });

    _loading = false;
  }

  Widget _buildErrorCard() {
    return buildErrorCard(tr("Could not get the list of posts !"));
  }

  Widget _buildNoPostNotice() {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text(tr("There is no post to display here yet.")),
      ),
    );
  }

  Widget _buildListView() {
    return RefreshIndicator(
      child: ListView.builder(
        itemCount: _list.length,
        itemBuilder: _buildItem,
        controller: _scrollController,
      ),
      onRefresh: () => _loadPostsList(),
    );
  }

  Widget _buildColumn() {
    return Column(
      children: List.generate(
        _list.length,
        (i) => _buildItem(null, i),
      ),
    );
  }

  Widget _buildItem(BuildContext context, int index) {
    return PostTile(
      post: _list[index],
      usersInfo: _users,
      groupsInfo: _groups,
      onDeletedPost: _removePost,
      showPostTarget: widget.showPostsTarget,
      userNamesClickable: widget.userNamesClickable,
    );
  }

  @override
  Widget build(BuildContext context) {
    if (_error == ErrorLevel.MAJOR) return _buildErrorCard();
    if (_list == null) return buildCenteredProgressBar();
    if (_list.length == 0) return _buildNoPostNotice();
    return widget.buildListView ? _buildListView() : _buildColumn();
  }

  void _removePost(Post post) => setState(() => _list.remove(post));

  void _reachedPostsBottom() {
    if (widget.getOlder != null) _loadPostsList(getOlder: true);
  }
}