import 'package:flutter/material.dart';
import '../ui_constants.dart';

/// A custom button widget with different variants and icon support.
class UiButton extends StatelessWidget {
  /// The text to display on the button.
  final String? text;

  /// Optional custom child widget. If provided, overrides text and icons.
  final Widget? child;

  /// Callback when the button is tapped.
  final VoidCallback? onPressed;

  /// Optional leading icon.
  final IconData? leadingIcon;

  /// Optional trailing icon.
  final IconData? trailingIcon;

  /// Optional Style
  final ButtonStyle? style;

  /// The size of the icons. Defaults to 20.
  final double iconSize;

  /// The size of the button.
  final UiButtonSize size;

  /// Whether the button should take up the full width of its container.
  final bool fullWidth;

  /// The button widget to use (ElevatedButton, OutlinedButton, or TextButton).
  final Widget Function(
    BuildContext context,
    VoidCallback? onPressed,
    ButtonStyle? style,
    Widget child,
  )
  buttonBuilder;

  /// Creates a [UiButton] with a custom button builder.
  const UiButton({
    super.key,
    this.text,
    this.child,
    required this.buttonBuilder,
    this.onPressed,
    this.leadingIcon,
    this.trailingIcon,
    this.style,
    this.iconSize = 20,
    this.size = UiButtonSize.medium,
    this.fullWidth = false,
  }) : assert(
         text != null || child != null,
         'Either text or child must be provided',
       );

  /// Creates a primary button using [ElevatedButton].
  UiButton.primary({
    super.key,
    this.text,
    this.child,
    this.onPressed,
    this.leadingIcon,
    this.trailingIcon,
    this.style,
    this.iconSize = 20,
    this.size = UiButtonSize.medium,
    this.fullWidth = false,
  }) : buttonBuilder = _elevatedButtonBuilder,
       assert(
         text != null || child != null,
         'Either text or child must be provided',
       );

  /// Creates a secondary button using [OutlinedButton].
  UiButton.secondary({
    super.key,
    this.text,
    this.child,
    this.onPressed,
    this.leadingIcon,
    this.trailingIcon,
    this.style,
    this.iconSize = 20,
    this.size = UiButtonSize.medium,
    this.fullWidth = false,
  }) : buttonBuilder = _outlinedButtonBuilder,
       assert(
         text != null || child != null,
         'Either text or child must be provided',
       );

  /// Creates a text button using [TextButton].
  UiButton.text({
    super.key,
    this.text,
    this.child,
    this.onPressed,
    this.leadingIcon,
    this.trailingIcon,
    this.style,
    this.iconSize = 20,
    this.size = UiButtonSize.medium,
    this.fullWidth = false,
  }) : buttonBuilder = _textButtonBuilder,
       assert(
         text != null || child != null,
         'Either text or child must be provided',
       );

  /// Creates a ghost button (transparent background).
  UiButton.ghost({
    super.key,
    this.text,
    this.child,
    this.onPressed,
    this.leadingIcon,
    this.trailingIcon,
    this.style,
    this.iconSize = 20,
    this.size = UiButtonSize.medium,
    this.fullWidth = false,
  }) : buttonBuilder = _textButtonBuilder,
       assert(
         text != null || child != null,
         'Either text or child must be provided',
       );

  @override
  /// Builds the button UI.
  Widget build(BuildContext context) {
    final Widget button = buttonBuilder(
      context,
      onPressed,
      style,
      _buildButtonContent(),
    );

    if (fullWidth) {
      return SizedBox(width: double.infinity, child: button);
    }

    return button;
  }

  /// Builds the button content with optional leading and trailing icons.
  Widget _buildButtonContent() {
    if (child != null) {
      return child!;
    }

    final String buttonText = text ?? '';

    // Optimization: If no icons, return plain text to avoid Row layout overhead
    if (leadingIcon == null && trailingIcon == null) {
      return Text(buttonText, textAlign: TextAlign.center);
    }

    // Multiple elements case: Use a Row with MainAxisSize.min
    final List<Widget> children = <Widget>[];

    if (leadingIcon != null) {
      children.add(Icon(leadingIcon, size: iconSize));
    }

    if (buttonText.isNotEmpty) {
      if (leadingIcon != null) {
        children.add(const SizedBox(width: UiConstants.space2));
      }
      // Use flexible to ensure text doesn't force infinite width in flex parents
      children.add(
        Flexible(
          child: Text(
            buttonText,
            textAlign: TextAlign.center,
            overflow: TextOverflow.ellipsis,
          ),
        ),
      );
    }

    if (trailingIcon != null) {
      if (buttonText.isNotEmpty || leadingIcon != null) {
        children.add(const SizedBox(width: UiConstants.space2));
      }
      children.add(Icon(trailingIcon, size: iconSize));
    }

    return Row(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.center,
      children: children,
    );
  }

  /// Builder for ElevatedButton.
  static Widget _elevatedButtonBuilder(
    BuildContext context,
    VoidCallback? onPressed,
    ButtonStyle? style,
    Widget child,
  ) {
    return ElevatedButton(onPressed: onPressed, style: style, child: child);
  }

  /// Builder for OutlinedButton.
  static Widget _outlinedButtonBuilder(
    BuildContext context,
    VoidCallback? onPressed,
    ButtonStyle? style,
    Widget child,
  ) {
    return OutlinedButton(onPressed: onPressed, style: style, child: child);
  }

  /// Builder for TextButton.
  static Widget _textButtonBuilder(
    BuildContext context,
    VoidCallback? onPressed,
    ButtonStyle? style,
    Widget child,
  ) {
    return TextButton(onPressed: onPressed, style: style, child: child);
  }
}

/// Defines the size of a [UiButton].
enum UiButtonSize {
  /// Small button (compact)
  small,

  /// Medium button (standard)
  medium,

  /// Large button (prominent)
  large,
}
