import 'package:flutter/material.dart';

import 'package:fancy_password_field/fancy_password_field.dart';

import 'package:pweb/config/constants.dart';
import 'package:pweb/models/state/control_state.dart';
import 'package:pweb/widgets/password/password.dart';

import 'package:pweb/generated/i18n/app_localizations.dart';


class PasswordUiController extends StatefulWidget {
  final TextEditingController controller;
  final String? labelText;
  final ControlState state;

  const PasswordUiController({
    required this.controller,
    this.labelText,
    this.state = ControlState.enabled,
    super.key,
  });

  @override
  State<PasswordUiController> createState() => _PasswordUiControllerState();
}

class _PasswordUiControllerState extends State<PasswordUiController> {
  @override
  void initState() {
    super.initState();
    widget.controller.addListener(_onPasswordChanged);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_onPasswordChanged);
    super.dispose();
  }

  void _onPasswordChanged() => setState(() {});

  @override
  Widget build(BuildContext context) {
    final isEnabled = widget.state == ControlState.enabled;
    final specialRule = _SpecialCharacterValidationRule(
      customText: AppLocalizations.of(
        context,
      )!.passwordValidationRuleSpecialCharacter,
    );
    final value = widget.controller.text;
    final missing = _allRules(context, specialRule)
        .where((rule) => !rule.validate(value))
        .map((rule) => rule.name)
        .toList(growable: false);
    final hasMissingRules = value.isNotEmpty && missing.isNotEmpty;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        IgnorePointer(
          ignoring: !isEnabled,
          child: Opacity(
            opacity: isEnabled ? 1 : 0.6,
            child: Theme(
              data: hasMissingRules
                  ? _invalidTheme(context)
                  : Theme.of(context),
              child: defaulRulesPasswordField(
                context,
                controller: widget.controller,
                labelText: widget.labelText,
                additionalRules: {specialRule},
                validationRuleBuilder: (_, _) => const SizedBox.shrink(),
              ),
            ),
          ),
        ),
        if (hasMissingRules) ...[
          const SizedBox(height: 8),
          ...missing.map(
            (ruleText) => Padding(
              padding: const EdgeInsets.only(bottom: 2),
              child: Text(
                '• $ruleText',
                style: TextStyle(color: Theme.of(context).colorScheme.error),
              ),
            ),
          ),
        ],
      ],
    );
  }

  List<ValidationRule> _allRules(
    BuildContext context,
    ValidationRule specialRule,
  ) {
    final loc = AppLocalizations.of(context)!;
    return [
      DigitValidationRule(customText: loc.passwordValidationRuleDigit),
      UppercaseValidationRule(customText: loc.passwordValidationRuleUpperCase),
      LowercaseValidationRule(customText: loc.passwordValidationRuleLowerCase),
      MinCharactersValidationRule(
        Constants.minPasswordCharacters,
        customText: loc.passwordValidationRuleMinCharacters(
          Constants.minPasswordCharacters,
        ),
      ),
      specialRule,
    ];
  }

  ThemeData _invalidTheme(BuildContext context) {
    final theme = Theme.of(context);
    final errorColor = theme.colorScheme.error;
    final border = OutlineInputBorder(
      borderRadius: BorderRadius.circular(4),
      borderSide: BorderSide(color: errorColor, width: 1.2),
    );

    return theme.copyWith(
      inputDecorationTheme: theme.inputDecorationTheme.copyWith(
        enabledBorder: border,
        focusedBorder: border,
        errorBorder: border,
        focusedErrorBorder: border,
      ),
    );
  }
}

class _SpecialCharacterValidationRule extends ValidationRule {
  final String customText;

  _SpecialCharacterValidationRule({required this.customText});

  @override
  String get name => customText;

  @override
  bool get showName => true;

  @override
  bool validate(String value) => value.runes.any(_isAsciiSpecialCharacter);

  bool _isAsciiSpecialCharacter(int code) =>
      (code >= 33 && code <= 47) ||
      (code >= 58 && code <= 64) ||
      (code >= 91 && code <= 96) ||
      (code >= 123 && code <= 126);
}
