import 'package:comunic/helpers/friends_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/friends_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/friend.dart';
import 'package:comunic/ui/tiles/accepted_friend_tile.dart';
import 'package:comunic/ui/tiles/pending_friend_tile.dart';
import 'package:comunic/ui/widgets/safe_state.dart';
import 'package:comunic/utils/conversations_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';

/// Friends list screen
///
/// Display the list of friends of the current user
///
/// @author Pierre HUBERT

enum _ErrorsLevel { NONE, MINOR, MAJOR }

class FriendsListScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _FriendsListScreenState();
}

class _FriendsListScreenState extends SafeState<FriendsListScreen> {
  /// Helpers
  final _friendsHelper = FriendsHelper();
  final _usersHelper = UsersHelper();

  /// Widget members
  _ErrorsLevel _error = _ErrorsLevel.NONE;
  FriendsList _friendsList;
  UsersList _usersInfo;
  GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
      GlobalKey<RefreshIndicatorState>();

  /// Useful setters
  set error(_ErrorsLevel err) => setState(() => _error = err);

  void _gotError() {
    error = _friendsList == null ? _ErrorsLevel.MAJOR : _ErrorsLevel.MINOR;
  }


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

  /// Initialize list retrieving
  Future<void> _getList() async {
    await _loadList(false);
    await _loadList(true);
  }

  /// Refresh the list of friends
  Future<void> _refreshList() async {
    await _refreshIndicatorKey.currentState.show();
  }

  /// Load the list of friends
  Future<void> _loadList(bool online) async {
    error = _ErrorsLevel.NONE;

    // Get the list of friends
    final list = await _friendsHelper.getList(online: online);

    // Check if there is no cache yet
    if(!online && list.isEmpty) return;

    // Check for errors
    if (list == null) return _gotError();

    // Get information about related users
    final users = await _usersHelper.getUsersInfo(list.usersId);

    // Check for errors
    if (users == null) return _gotError();

    // Apply new information
    setState(() {
      _friendsList = list..sort();
      _usersInfo = users;
    });
    error = _ErrorsLevel.NONE;
  }

  /// Build and return loading error
  Widget _buildError() => buildErrorCard(
        tr("Could not load your list of friends!"),
        actions: [
          FlatButton(
            onPressed: _refreshList,
            child: Text(
              tr("Retry").toUpperCase(),
              style: TextStyle(color: Colors.white),
            ),
          ),
        ],
      );

  @override
  Widget build(BuildContext context) {
    if (_error == _ErrorsLevel.MAJOR) return _buildError();
    if (_friendsList == null) return buildCenteredProgressBar();

    return Column(
      children: <Widget>[
        // Check for errors
        Container(child: _error != _ErrorsLevel.NONE ? _buildError() : null),

        // List of friends
        Expanded(
          child: RefreshIndicator(
            key: _refreshIndicatorKey,
            onRefresh: () => _loadList(true),
            child: ListView.builder(
                physics: AlwaysScrollableScrollPhysics(),
                itemCount: _friendsList.length,
                itemBuilder: (c, i) => _friendsList[i].accepted
                    ? AcceptedFriendTile(
                        friend: _friendsList[i],
                        user: _usersInfo.getUser(_friendsList[i].id),
                        onOpenPrivateConversation: _openPrivateConversation,
                        onSetFollowing: _setFollowingFriend,
                        onRequestDelete: _deleteFriend,
                      )
                    : PendingFriendTile(
                        friend: _friendsList[i],
                        user: _usersInfo.getUser(_friendsList[i].id),
                        onRespond: _respondRequest,
                      )),
          ),
        ),
      ],
    );
  }

  /// Respond to friendship request
  Future<void> _respondRequest(Friend f, bool accept) async {
    if (!await _friendsHelper.respondRequest(f.id, accept))
      showSimpleSnack(context, tr("Could not respond to friendship request!"));

    // Load the list of friends again
    _refreshList();
  }

  /// Update following status of a friend
  Future<void> _setFollowingFriend(Friend friend, bool follow) async {
    if (!await _friendsHelper.setFollowing(friend.id, follow))
      showSimpleSnack(context, tr("Could not update following status!"));

    _refreshList();
  }

  /// Handles deletion request of a friend
  Future<void> _deleteFriend(Friend f) async {
    final choice = await showDialog<bool>(
      context: context,
      builder: (b) => AlertDialog(
            title: Text(tr("Delete friend")),
            content: Text(tr(
                "Are you sure do you want to remove this friend from your list of friends ? A friendship request will have to be sent to get this user back to your list!")),
            actions: <Widget>[
              FlatButton(
                onPressed: () => Navigator.pop(context, false),
                child: Text(tr("Cancel").toUpperCase()),
              ),
              FlatButton(
                onPressed: () => Navigator.pop(context, true),
                child: Text(
                  tr("Confirm").toUpperCase(),
                  style: TextStyle(color: Colors.red),
                ),
              ),
            ],
          ),
    );

    if (choice == null || !choice) return;

    // Forward the request to the server
    if (!await _friendsHelper.removeFriend(f.id))
      showSimpleSnack(
          context, tr("Could not delete this person from your friends list!"));

    // Refresh list
    _refreshList();
  }

  /// Open a private conversation for a given [friend]
  Future<void> _openPrivateConversation(Friend friend) async {
    await openPrivateConversation(context, friend.id);
  }
}