import 'package:comunic/helpers/search_helper.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/user.dart';
import 'package:comunic/ui/tiles/simple_user_tile.dart';
import 'package:flutter/material.dart';

/// Pick user widget
///
/// Allows to choose a user by starting to type his name and tapping on it
/// when his name appear
///
/// @author Pierre HUBERT

typedef OnSelectUserCallback = void Function(User);

class PickUserWidget extends StatefulWidget {
  final OnSelectUserCallback onSelectUser;
  final void Function(String) onValueChange;
  final String label;
  final bool resetOnChoose;
  final bool keepFocusOnChoose;
  final bool enabled;

  const PickUserWidget({
    Key key,
    @required this.onSelectUser,
    @required this.label,
    this.resetOnChoose = false,
    this.keepFocusOnChoose = false,
    this.onValueChange,
    this.enabled = true,
  })  : assert(onSelectUser != null),
        assert(label != null),
        assert(resetOnChoose != null),
        assert(keepFocusOnChoose != null),
        super(key: key);

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

class _PickUserWidgetState extends State<PickUserWidget> {
  // Helper
  final SearchHelper _searchHelper = SearchHelper();

  // Widget properties
  final FocusNode _focusNode = FocusNode();
  final TextEditingController _controller = TextEditingController();
  OverlayEntry _overlayEntry;
  UsersList _suggestions;

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

    _focusNode.addListener(() {
      if (_focusNode.hasFocus) {
        //Check for focus
        //_showOverlay();
      } else {
        //Remove overlay
        _removeOverlay();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      focusNode: _focusNode,
      onChanged: (s) => _updateSuggestions(),
      controller: _controller,
      enabled: widget.enabled,
      decoration: InputDecoration(
        labelText: widget.label,
        alignLabelWithHint: true,
      ),
    );
  }

  OverlayEntry _createOverlayEntry() {
    RenderBox renderBox = context.findRenderObject();
    final size = renderBox.size;
    final offset = renderBox.localToGlobal(Offset.zero);

    return OverlayEntry(builder: (c) {
      return Positioned(
        left: offset.dx,
        top: offset.dy + size.height + 5.0,
        width: size.width,
        child: Material(
          elevation: 4.0,
          child: ListView.builder(
            padding: EdgeInsets.zero,
            shrinkWrap: true,
            itemCount: _suggestions == null ? 0 : _suggestions.length,
            itemBuilder: (c, i) => SimpleUserTile(
              user: _suggestions[i],
              onTap: _userTapped,
            ),
          ),
        ),
      );
    });
  }

  void _showOverlay() {
    _overlayEntry = _createOverlayEntry();
    Overlay.of(context).insert(_overlayEntry);
  }

  void _removeOverlay() {
    if (_overlayEntry != null) {
      _overlayEntry.remove();
      _overlayEntry = null;
    }
  }

  /// This method get called each time the input value is updated
  Future<void> _updateSuggestions() async {
    if (widget.onValueChange != null) widget.onValueChange(_controller.text);

    if (_controller.text.length == 0) return _removeOverlay();

    final results = await _searchHelper.searchUser(_controller.text);

    if (results == null) return;

    _suggestions = results;
    if (_overlayEntry != null)
      _overlayEntry.markNeedsBuild();
    else
      _showOverlay();
  }

  /// Method called each time a user is tapped (selected)
  void _userTapped(User user) {
    // Hide overlay
    _removeOverlay();

    // Unfocus if required
    if (!widget.keepFocusOnChoose) {
      _focusNode.unfocus();
    }

    //Check if name has to remain in input
    if (widget.resetOnChoose) {
      _controller.text = "";
    } else
      _controller.text = user.fullName;

    //Callback
    widget.onSelectUser(user);
  }
}