// ABOUTME: Validated number input field widget with real-time feedback and comprehensive error handling
// ABOUTME: Provides consistent number input validation across all forms in the app
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ValidatedNumberField extends StatefulWidget {
  final String label;
  final String? hintText;
  final double? initialValue;
  final double? minValue;
  final double? maxValue;
  final int? decimalPlaces;
  final String? suffix;
  final bool isRequired;
  final ValueChanged<double?>? onChanged;
  final String? Function(double?)? validator;
  final List<String> warnings;
  final bool showWarnings;
  final TextEditingController? controller;
  final FocusNode? focusNode;
  final TextInputAction? textInputAction;
  final VoidCallback? onEditingComplete;

  const ValidatedNumberField({
    super.key,
    required this.label,
    this.hintText,
    this.initialValue,
    this.minValue,
    this.maxValue,
    this.decimalPlaces = 2,
    this.suffix,
    this.isRequired = false,
    this.onChanged,
    this.validator,
    this.warnings = const [],
    this.showWarnings = true,
    this.controller,
    this.focusNode,
    this.textInputAction,
    this.onEditingComplete,
  });

  @override
  State<ValidatedNumberField> createState() => _ValidatedNumberFieldState();
}

class _ValidatedNumberFieldState extends State<ValidatedNumberField> {
  late TextEditingController _controller;
  late FocusNode _focusNode;
  String? _errorText;
  List<String> _currentWarnings = [];
  double? _currentValue;
  bool _hasUserInput = false;

  @override
  void initState() {
    super.initState();
    _controller = widget.controller ?? TextEditingController();
    _focusNode = widget.focusNode ?? FocusNode();
    
    if (widget.initialValue != null) {
      _controller.text = widget.initialValue!.toStringAsFixed(widget.decimalPlaces ?? 2);
      _currentValue = widget.initialValue;
    }
    
    _controller.addListener(_onTextChanged);
    _focusNode.addListener(_onFocusChanged);
    
    // Initial validation
    _validateInput(_currentValue, showErrors: false);
  }

  @override
  void dispose() {
    if (widget.controller == null) {
      _controller.dispose();
    }
    if (widget.focusNode == null) {
      _focusNode.dispose();
    }
    super.dispose();
  }

  void _onTextChanged() {
    final text = _controller.text;
    double? value;
    
    if (text.isNotEmpty) {
      value = double.tryParse(text);
      _hasUserInput = true;
    } else {
      value = null;
      _hasUserInput = true;
    }
    
    if (value != _currentValue) {
      _currentValue = value;
      widget.onChanged?.call(value);
      _validateInput(value, showErrors: _hasUserInput);
    }
  }

  void _onFocusChanged() {
    if (!_focusNode.hasFocus && _hasUserInput) {
      // Validate when field loses focus
      _validateInput(_currentValue, showErrors: true);
    }
  }

  void _validateInput(double? value, {required bool showErrors}) {
    String? error;
    List<String> warnings = [];
    
    // Required field validation
    if (widget.isRequired && (value == null)) {
      error = '${widget.label} is required';
    }
    
    // Range validation
    if (value != null) {
      if (widget.minValue != null && value < widget.minValue!) {
        error = '${widget.label} must be at least ${widget.minValue}';
      } else if (widget.maxValue != null && value > widget.maxValue!) {
        error = '${widget.label} must not exceed ${widget.maxValue}';
      }
    }
    
    // Custom validation
    if (error == null && widget.validator != null) {
      error = widget.validator!(value);
    }
    
    // Warning checks
    if (value != null && widget.showWarnings) {
      // Add range warnings (different from errors - these are advisory)
      if (widget.minValue != null && widget.maxValue != null) {
        final range = widget.maxValue! - widget.minValue!;
        final lowThreshold = widget.minValue! + (range * 0.1); // 10% above minimum
        final highThreshold = widget.maxValue! - (range * 0.1); // 10% below maximum
        
        if (value < lowThreshold) {
          warnings.add('${widget.label} is quite low. Please verify this is correct.');
        } else if (value > highThreshold) {
          warnings.add('${widget.label} is quite high. Please verify this is correct.');
        }
      }
      
      // Add any external warnings
      warnings.addAll(widget.warnings);
    }
    
    setState(() {
      _errorText = showErrors ? error : null;
      _currentWarnings = warnings;
    });
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final hasError = _errorText != null;
    final hasWarnings = _currentWarnings.isNotEmpty && widget.showWarnings;
    
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // Label
        RichText(
          text: TextSpan(
            text: widget.label,
            style: theme.textTheme.titleMedium?.copyWith(
              fontWeight: FontWeight.w600,
            ),
            children: [
              if (widget.isRequired)
                TextSpan(
                  text: ' *',
                  style: TextStyle(
                    color: theme.colorScheme.error,
                    fontWeight: FontWeight.w600,
                  ),
                ),
            ],
          ),
        ),
        const SizedBox(height: 8),
        
        // Input field
        TextField(
          controller: _controller,
          focusNode: _focusNode,
          keyboardType: TextInputType.numberWithOptions(
            decimal: (widget.decimalPlaces ?? 0) > 0,
            signed: false,
          ),
          inputFormatters: [
            if (widget.decimalPlaces != null && widget.decimalPlaces! > 0)
              FilteringTextInputFormatter.allow(
                RegExp(r'^\d*\.?\d{0,' + widget.decimalPlaces.toString() + '}'),
              )
            else
              FilteringTextInputFormatter.digitsOnly,
          ],
          textInputAction: widget.textInputAction,
          onEditingComplete: widget.onEditingComplete,
          decoration: InputDecoration(
            hintText: widget.hintText,
            suffixText: widget.suffix,
            errorText: _errorText,
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
            ),
            errorBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: theme.colorScheme.error),
            ),
            focusedErrorBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: theme.colorScheme.error, width: 2),
            ),
            // Warning border
            enabledBorder: hasWarnings && !hasError
                ? OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: BorderSide(color: Colors.orange.shade400),
                  )
                : null,
            focusedBorder: hasWarnings && !hasError
                ? OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: BorderSide(color: Colors.orange.shade400, width: 2),
                  )
                : null,
            contentPadding: const EdgeInsets.symmetric(
              horizontal: 12,
              vertical: 16,
            ),
            suffixStyle: theme.textTheme.bodySmall?.copyWith(
              color: theme.colorScheme.onSurfaceVariant,
            ),
          ),
        ),
        
        // Warnings display
        if (hasWarnings && !hasError) ...[
          const SizedBox(height: 4),
          ...(_currentWarnings.map((warning) => Container(
            margin: const EdgeInsets.only(bottom: 2),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Icon(
                  Icons.warning_amber,
                  size: 14,
                  color: Colors.orange.shade600,
                ),
                const SizedBox(width: 4),
                Expanded(
                  child: Text(
                    warning,
                    style: theme.textTheme.bodySmall?.copyWith(
                      color: Colors.orange.shade700,
                    ),
                  ),
                ),
              ],
            ),
          ))),
        ],
        
        // Helper text with range info
        if (widget.minValue != null || widget.maxValue != null) ...[
          const SizedBox(height: 4),
          Text(
            _getRangeText(),
            style: theme.textTheme.bodySmall?.copyWith(
              color: theme.colorScheme.onSurfaceVariant,
            ),
          ),
        ],
      ],
    );
  }

  String _getRangeText() {
    if (widget.minValue != null && widget.maxValue != null) {
      return 'Valid range: ${widget.minValue} - ${widget.maxValue}${widget.suffix ?? ''}';
    } else if (widget.minValue != null) {
      return 'Minimum: ${widget.minValue}${widget.suffix ?? ''}';
    } else if (widget.maxValue != null) {
      return 'Maximum: ${widget.maxValue}${widget.suffix ?? ''}';
    }
    return '';
  }
}

/// Extension methods for common validation patterns
extension ValidatedNumberFieldValidators on ValidatedNumberField {
  /// Create a validator for weight values
  static String? weightValidator(double? value) {
    if (value == null) return null;
    
    if (value <= 0) {
      return 'Weight must be greater than 0';
    }
    if (value < 20) {
      return 'Weight seems too low (minimum: 20kg)';
    }
    if (value > 635) {
      return 'Weight exceeds maximum limit (635kg)';
    }
    
    return null;
  }
  
  /// Create a validator for blood pressure values
  static String? bloodPressureValidator(double? value, {bool isSystolic = true}) {
    if (value == null) return null;
    
    final intValue = value.round();
    if (isSystolic) {
      if (intValue < 60) {
        return 'Systolic pressure too low (minimum: 60 mmHg)';
      }
      if (intValue > 300) {
        return 'Systolic pressure too high (maximum: 300 mmHg)';
      }
    } else {
      if (intValue < 30) {
        return 'Diastolic pressure too low (minimum: 30 mmHg)';
      }
      if (intValue > 200) {
        return 'Diastolic pressure too high (maximum: 200 mmHg)';
      }
    }
    
    return null;
  }
}
