import 'package:comunic/enums/load_error_level.dart';
import 'package:comunic/helpers/conversations_helper.dart';
import 'package:comunic/helpers/events_helper.dart';
import 'package:comunic/helpers/groups_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/conversations_list.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/conversation.dart';
import 'package:comunic/ui/routes/main_route/main_route.dart';
import 'package:comunic/ui/screens/create_conversation_screen.dart';
import 'package:comunic/ui/tiles/conversation_tile.dart';
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';

/// Conversations screen
///
/// @author Pierre HUBERT

class ConversationsListScreen extends StatefulWidget {
  final bool useSmallFAB;
  final Function() onOpen;

  const ConversationsListScreen({
    Key key,
    this.useSmallFAB = false,
    this.onOpen,
  })  : assert(useSmallFAB != null),
        super(key: key);

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

class _ConversationScreenState extends SafeState<ConversationsListScreen> {
  final ConversationsHelper _conversationsHelper = ConversationsHelper();
  final UsersHelper _usersHelper = UsersHelper();
  ConversationsList _list;
  UsersList _users;
  GroupsList _groups;
  LoadErrorLevel _error = LoadErrorLevel.NONE;
  final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
      GlobalKey<RefreshIndicatorState>();

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

    this.listen<NewNumberUnreadConversations>(
        (d) => _refreshIndicatorKey.currentState.show());
  }

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

  void setError(LoadErrorLevel err) => setState(() => _error = err);

  /// Get the list of conversations, once from the cache, once from the server
  Future<void> _loadConversations() async {
    await _loadConversationsList(true);
    await _loadConversationsList(false);
  }

  /// Load the list of conversations
  Future<void> _loadConversationsList(bool cached) async {
    setError(LoadErrorLevel.NONE);

    try {
      ConversationsList list = cached
          ? await _conversationsHelper.getCachedList()
          : await _conversationsHelper.downloadList();
      assert(list != null);

      // Get information about the members of the conversations
      _users = await _usersHelper.getList(list.allUsersID);

      _groups = await GroupsHelper().getListOrThrow(list.allGroupsID);

      setState(() => _list = list);
    } catch (e, s) {
      debugPrint("Failed to get conversations list! $e => $s", wrapWidth: 1024);
      setError(_list == null ? LoadErrorLevel.MAJOR : LoadErrorLevel.MINOR);
    }
  }

  /// Build an error card
  Widget _buildErrorCard() {
    return buildErrorCard(
      tr("Could not retrieve the list of conversations!"),
      actions: <Widget>[
        TextButton(
          onPressed: () => _refreshIndicatorKey.currentState.show(),
          child: Text(
            tr("Retry").toUpperCase(),
            style: TextStyle(
              color: Colors.white,
            ),
          ),
        )
      ],
    );
  }

  /// Open a conversation
  void _openConversation(Conversation conv) {
    MainController.of(context).openConversation(conv);
    if (widget.onOpen != null) widget.onOpen();
  }

  /// Create a new conversation
  void _createConversation() {
    MainController.of(context)
        .push(CreateConversationScreen(), canShowAsDialog: true);
    if (widget.onOpen != null) widget.onOpen();
  }

  /// Handle conversations updated requests
  void _updateConversation(Conversation conversation) {
    MainController.of(context).openConversationSettingsRoute(conversation);
  }

  /// Handle conversation deletion request
  Future<void> _requestLeaveConversation(Conversation conversation) async {
    if (conversation.isGroupConversation) {
      showAlert(
          context: context,
          title: tr("Group conversation"),
          message: tr(
              "This conversation is managed by a group. You can not leave it this way. If you do not want to receive notifications from this conversation anymore, you can stop following it in the conversation settings"));
      return;
    }

    final result = await showConfirmDialog(
        context: context,
        message: conversation.isLastAdmin
            ? tr(
                "Do you really want to leave this conversation ? As you are its last admin, it will be completely deleted!")
            : tr("Do you really want to leave this conversation ?"));

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

    // Request the conversation to be deleted now
    try {
      await _conversationsHelper.deleteConversation(conversation.id);
    } catch (e, s) {
      print("Failed to leave conversation! $e => $s");
      ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text(tr("Could not leave the conversation!"))));
    }

    // Reload the list of conversations
    _loadConversationsList(false);
  }

  @override
  Widget build(BuildContext context) {
    if (_error == LoadErrorLevel.MAJOR) return _buildErrorCard();
    if (_list == null) return buildCenteredProgressBar();

    // Show the list of conversations
    return Stack(
      children: <Widget>[
        Column(
          children: <Widget>[
            Container(
              child: _error == LoadErrorLevel.MINOR ? _buildErrorCard() : null,
            ),
            Expanded(
              child: RefreshIndicator(
                onRefresh: () => _loadConversationsList(false),
                key: _refreshIndicatorKey,
                child: ListView.builder(
                  physics: AlwaysScrollableScrollPhysics(),
                  controller: ScrollController(),
                  itemBuilder: (context, index) {
                    if (_list[index].isGroupConversation &&
                        !_list[index].following) return Container();

                    return ConversationTile(
                      conversation: _list.elementAt(index),
                      usersList: _users,
                      groupsList: _groups,
                      onOpen: (c) {
                        _openConversation(c);
                      },
                      onRequestUpdate: _updateConversation,
                      onRequestLeave: _requestLeaveConversation,
                    );
                  },
                  itemCount: _list.length,
                ),
              ),
            ),
          ],
        ),

        // Add conversation button
        Positioned(
          right: widget.useSmallFAB ? 5.0 : 20.0,
          bottom: widget.useSmallFAB ? 5.0 : 20.0,
          child: FloatingActionButton(
            mini: widget.useSmallFAB,
            onPressed: () => _createConversation(),
            child: Icon(Icons.add),
          ),
        ),
      ],
    );
  }
}