import 'package:comunic/helpers/account_helper.dart';
import 'package:comunic/ui/routes/password_reset_route.dart';
import 'package:comunic/ui/widgets/dialogs/cancel_dialog_button.dart';
import 'package:comunic/ui/widgets/safe_state.dart';
import 'package:comunic/utils/input_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

/// Reset password route
///
/// @author Pierre Hubert

class ResetPasswordRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(tr("Password forgotten")),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Center(
          child: ConstrainedBox(
            constraints: BoxConstraints(maxWidth: 300),
            child: SingleChildScrollView(child: _ResetPasswordBody()),
          ),
        ),
      ),
    );
  }
}

enum _SelectedOption { NONE, SECURITY_QUESTIONS }

class _ResetPasswordBody extends StatefulWidget {
  @override
  _ResetPasswordBodyState createState() => _ResetPasswordBodyState();
}

class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
  var _loading = false;

  /// Step 1 - check email address
  String _emailAddress;
  final _emailController = TextEditingController();

  String get _inputEmail => _emailController.text;

  bool get _isEmailValid =>
      _inputEmail.isNotEmpty && validateEmail(_inputEmail);

  /// Step 2 - Offer options
  bool _hasSecurityQuestions;

  var _selectedOption = _SelectedOption.NONE;

  void _setLoading(bool loading) => setState(() => _loading = loading);

  /// Step 3b - Answer security questions
  List<String> _questions;
  var _questionsControllers = List<TextEditingController>();

  List<String> get _answers =>
      _questionsControllers.map((f) => f.text).toList();

  bool get _canSubmitAnswers => _answers.every((f) => f.isNotEmpty);

  @override
  Widget build(BuildContext context) {
    if (_loading) return buildCenteredProgressBar();

    if (_emailAddress == null) return _buildEnterEmailAddressScreen();

    switch (_selectedOption) {
      case _SelectedOption.NONE:
        return _buildOptionsScreen();

      case _SelectedOption.SECURITY_QUESTIONS:
        return _buildSecurityQuestionsScreen();
    }

    throw Exception("Unreachable statement!");
  }

  Widget _buildEnterEmailAddressScreen() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Text(tr("Please enter your email address to reset your password:")),
        TextField(
          controller: _emailController,
          onChanged: (s) => setState(() {}),
          onSubmitted: _isEmailValid ? (s) => _checkEmail() : null,
          textInputAction: TextInputAction.done,
          keyboardType: TextInputType.emailAddress,
          decoration: InputDecoration(
            icon: Icon(Icons.email),
            alignLabelWithHint: true,
            labelText: tr("Email address..."),
            suffixIcon: IconButton(
              icon: Icon(Icons.check),
              onPressed: _isEmailValid ? _checkEmail : null,
            ),
            errorText: _inputEmail.isEmpty || _isEmailValid
                ? null
                : tr("Invalid email address!"),
          ),
        ),
      ],
    );
  }

  /// Check given email address
  void _checkEmail() async {
    try {
      _setLoading(true);

      // Check if email address exists or not
      if (!await AccountHelper.existsMailAccount(_inputEmail)) {
        _setLoading(false);
        showSimpleSnack(context, tr("Specified email address was not found!"));
        return;
      }

      _hasSecurityQuestions =
          await AccountHelper.hasSecurityQuestions(_inputEmail);

      // We retain email address only if everything went well
      _emailAddress = _inputEmail;
      _setLoading(false);
    } catch (e, s) {
      print("Could not check given email! $e\n$s");
      showSimpleSnack(
          context, tr("An error occurred while checking your options !"));
      _setLoading(false);
    }
  }

  /// Offer the user the options he has to reset his account
  Widget _buildOptionsScreen() => Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Text(tr("Here are your options to reset your account:")),
          _Spacer(),
          OutlineButton.icon(
            onPressed: _openSendEmailDialog,
            icon: Icon(Icons.email),
            label: Text(tr("Send us an email to ask for help")),
          ),
          _Spacer(visible: _hasSecurityQuestions),
          _hasSecurityQuestions
              ? OutlineButton.icon(
                  onPressed: _loadSecurityQuestions,
                  icon: Icon(Icons.help_outline),
                  label: Text(tr("Answer your security questions")),
                )
              : Container(),
        ],
      );

  /// Show a dialog with our email address
  void _openSendEmailDialog() {
    showDialog(
        context: context,
        builder: (c) => AlertDialog(
              title: Text("Contact us"),
              content: Text(tr("You can reach us at contact@communiquons.org")),
              actions: <Widget>[CancelDialogButton()],
            ));
  }

  /// Load security questions
  void _loadSecurityQuestions() async {
    _setLoading(true);
    try {
      _questions = await AccountHelper.getSecurityQuestions(_emailAddress);

      _questionsControllers =
          List.generate(_questions.length, (i) => TextEditingController());
      _selectedOption = _SelectedOption.SECURITY_QUESTIONS;
    } catch (e, s) {
      print("Could not load security questions! $e\n$s");
      showSimpleSnack(context, tr("Could not load your security questions!"));
    }
    _setLoading(false);
  }

  /// Show a screen to prompt security questions of the user
  Widget _buildSecurityQuestionsScreen() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[]
        ..add(Text(tr("Please answer now your security questions:")))
        ..add(_Spacer())
        ..addAll(List.generate(_questions.length, _buildSecurityQuestionField))
        ..add(_Spacer())
        ..add(OutlineButton(
          onPressed: _canSubmitAnswers ? _submitSecurityAnswers : null,
          child: Text(tr("Submit")),
        )),
    );
  }

  Widget _buildSecurityQuestionField(int id) => Column(
        children: <Widget>[
          Text(_questions[id]),
          TextField(
            controller: _questionsControllers[id],
            onChanged: (s) => setState(() {}),
            onSubmitted:
                _canSubmitAnswers ? (s) => _submitSecurityAnswers() : null,
            decoration: InputDecoration(
                alignLabelWithHint: false,
                labelText:
                    tr("Answer %num%", args: {"num": (id + 1).toString()})),
          ),
          _Spacer()
        ],
      );

  /// Submit security answers
  Future<void> _submitSecurityAnswers() async {
    _setLoading(true);
    try {
      final token = await AccountHelper.checkAnswers(_emailAddress, _answers);

      _useResetToken(token);
    } catch (e, s) {
      print("Could not submit security answers! $e\n$s");
      showSimpleSnack(
          context, tr("Could not validate these security answers!"));
    }
    _setLoading(false);
  }

  /// Call this method whenever the user managed to get a password reset token
  void _useResetToken(String token) => Navigator.of(context).pushReplacement(
      MaterialPageRoute(builder: (c) => PasswordResetRoute(token: token)));
}

class _Spacer extends StatelessWidget {
  final bool visible;

  const _Spacer({Key key, this.visible = true})
      : assert(visible != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: visible ? 35 : null,
    );
  }
}