import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/server_config.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:flutter/material.dart';

/// New password input widget
///
/// @author Pierre Hubert

class UserInfoForPassword {
  final String? firstName;
  final String? lastName;
  final String? email;

  const UserInfoForPassword({
    required this.firstName,
    required this.lastName,
    required this.email,
  });
}

class NewPasswordInputWidget extends StatefulWidget {
  final Widget? icon;
  final VoidCallback? onEdited;
  final VoidCallback? onSubmitted;
  final TextInputAction? textInputAction;
  final String label;

  final UserInfoForPassword user;

  const NewPasswordInputWidget({
    Key? key,
    this.icon,
    this.onEdited,
    this.onSubmitted,
    this.textInputAction,
    required this.label,
    required this.user,
  })  : super(key: key);

  @override
  NewPasswordInputWidgetState createState() => NewPasswordInputWidgetState();
}

class NewPasswordInputWidgetState extends State<NewPasswordInputWidget> {
  final TextEditingController _controller = TextEditingController();

  String get value => _controller.text;

  bool get valid => value.isNotEmpty && (_errorMessage ?? "").isEmpty;

  PasswordPolicy get _policy => ServerConfigurationHelper.config!.passwordPolicy;

  @override
  void didUpdateWidget(covariant NewPasswordInputWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) => TextField(
        controller: _controller,
        obscureText: true,
        onChanged: (s) => _onChanged(),
        onSubmitted:
            widget.onSubmitted == null ? null : (s) => widget.onSubmitted!(),
        textInputAction: widget.textInputAction,
        decoration: InputDecoration(
          errorText: _errorMessage,
          errorMaxLines: 3,
          icon: widget.icon,
          labelText: widget.label,
        ),
      );

  void _onChanged() {
    setState(() {});
    if (widget.onEdited != null) widget.onEdited!();
  }

  /// Generate an error message associated with current password
  String? get _errorMessage {
    if (value.isEmpty) return null;

    // Mandatory checks
    if (!_policy.allowMailInPassword &&
        (widget.user.email ?? "").isNotEmpty &&
        (widget.user.email!.toLowerCase().contains(value.toLowerCase()) ||
            value.toLowerCase().contains(widget.user.email!.toLowerCase()))) {
      return tr("Your password must not contains part of your email address!");
    }

    if (!_policy.allowNameInPassword &&
        (widget.user.firstName ?? "").isNotEmpty &&
        value.toLowerCase().contains(widget.user.firstName!.toLowerCase())) {
      return tr("Your password must not contains your first name!");
    }

    if (!_policy.allowNameInPassword &&
        (widget.user.lastName ?? "").isNotEmpty &&
        value.toLowerCase().contains(widget.user.lastName!.toLowerCase())) {
      return tr("Your password must not contains your last name!");
    }

    if (_policy.minPasswordLength > value.length) {
      return tr(
        "Your password must be composed of at least %num% characters!",
        args: {
          "num": _policy.minPasswordLength.toString(),
        },
      );
    }

    // Characteristics check
    var count = 0;

    if (_hasCharacteristic(RegExp(r'[A-Z]'), _policy.minNumberUpperCaseLetters))
      count++;

    if (_hasCharacteristic(RegExp(r'[a-z]'), _policy.minNumberLowerCaseLetters))
      count++;

    if (_hasCharacteristic(RegExp(r'[0-9]'), _policy.minNumberDigits)) count++;

    if (_hasCharacteristic(
        RegExp(r'[^A-Za-z0-9]'), _policy.minNumberSpecialCharacters)) count++;

    if (count >= _policy.minCategoriesPresence) return null;

    return tr(
      "Your password must contains characters of at least %num% of the following categories : %upper% upper case letter, %lower% lowercase letter, %digit% digit, %special% special character.",
      args: {
        "num": (_policy.minCategoriesPresence == 4
            ? tr("ALL")
            : _policy.minCategoriesPresence.toString()),
        "upper": _policy.minNumberUpperCaseLetters.toString(),
        "lower": _policy.minNumberLowerCaseLetters.toString(),
        "digit": _policy.minNumberDigits.toString(),
        "special": _policy.minNumberSpecialCharacters.toString(),
      },
    );
  }

  bool _hasCharacteristic(RegExp exp, int requiredCount) {
    if (requiredCount < 1) return true;

    return exp.allMatches(value).length >= requiredCount;
  }
}