import 'dart:math' as math;
import 'package:flutter/material.dart';

// How far the glow bleeds outside the child's bounds on each side.
const _kGlowSpread = 12.0;

/// Wraps any widget with a soft outward Gemini-colored glow that animates
/// while [isProcessing] is true and disappears when false.
/// The glow paints *outside* the child's bounds without affecting layout.
class GeminiAnimatedBorder extends StatefulWidget {
  final Widget child;
  final bool isProcessing;

  /// Must match the border-radius of the wrapped widget so the glow follows its shape.
  final double borderRadius;

  /// When true the glow uses DeepSeek blue tones instead of Gemini colours.
  final bool useDeepSeekColors;

  const GeminiAnimatedBorder({
    super.key,
    required this.child,
    required this.isProcessing,
    this.borderRadius = 8,
    this.useDeepSeekColors = false,
  });

  @override
  State<GeminiAnimatedBorder> createState() => _GeminiAnimatedBorderState();
}

class _GeminiAnimatedBorderState extends State<GeminiAnimatedBorder>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 3),
    );
    if (widget.isProcessing) _controller.repeat();
  }

  @override
  void didUpdateWidget(GeminiAnimatedBorder old) {
    super.didUpdateWidget(old);
    if (widget.isProcessing && !old.isProcessing) {
      _controller.repeat();
    } else if (!widget.isProcessing && old.isProcessing) {
      _controller.stop();
      _controller.reset();
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!widget.isProcessing) return widget.child;

    return AnimatedBuilder(
      animation: _controller,
      child: widget.child,
      builder: (context, child) {
        return Stack(
          clipBehavior: Clip.none,
          children: [
            // Glow layer positioned to bleed outside the child on all sides.
            Positioned(
              left: -_kGlowSpread,
              right: -_kGlowSpread,
              top: -_kGlowSpread,
              bottom: -_kGlowSpread,
              child: CustomPaint(
                painter: _GeminiGlowPainter(
                  rotation: _controller.value,
                  borderRadius: widget.borderRadius,
                  glowSpread: _kGlowSpread,
                  deepSeekMode: widget.useDeepSeekColors,
                ),
              ),
            ),
            child!,
          ],
        );
      },
    );
  }
}

/// Wraps a TextField with a rotating gradient border that animates with Gemini colors
/// when processing is active. Shows normal border appearance when not processing.
class GeminiAnimatedTextField extends StatefulWidget {
  final TextEditingController controller;
  final String? labelText;
  final int? maxLines;
  final bool enabled;
  final bool isProcessing;
  final InputDecoration? decoration;

  /// When true the glow uses DeepSeek blue tones instead of Gemini colours.
  final bool useDeepSeekColors;

  const GeminiAnimatedTextField({
    super.key,
    required this.controller,
    this.labelText,
    this.maxLines,
    this.enabled = true,
    this.isProcessing = false,
    this.decoration,
    this.useDeepSeekColors = false,
  });

  @override
  State<GeminiAnimatedTextField> createState() =>
      _GeminiAnimatedTextFieldState();
}

class _GeminiAnimatedTextFieldState extends State<GeminiAnimatedTextField>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 3),
    );
    if (widget.isProcessing) _controller.repeat();
  }

  @override
  void didUpdateWidget(GeminiAnimatedTextField oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.isProcessing && !oldWidget.isProcessing) {
      _controller.repeat();
    } else if (!widget.isProcessing && oldWidget.isProcessing) {
      _controller.stop();
      _controller.reset();
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final field = TextField(
      controller: widget.controller,
      enabled: widget.enabled && !widget.isProcessing,
      maxLines: widget.maxLines,
      decoration:
          widget.decoration ?? InputDecoration(labelText: widget.labelText),
    );

    if (!widget.isProcessing) return field;

    return AnimatedBuilder(
      animation: _controller,
      child: field,
      builder: (context, child) {
        return Stack(
          clipBehavior: Clip.none,
          children: [
            Positioned(
              left: -_kGlowSpread,
              right: -_kGlowSpread,
              top: -_kGlowSpread,
              bottom: -_kGlowSpread,
              child: CustomPaint(
                painter: _GeminiGlowPainter(
                  rotation: _controller.value,
                  borderRadius: 4,
                  glowSpread: _kGlowSpread,
                  deepSeekMode: widget.useDeepSeekColors,
                ),
              ),
            ),
            child!,
          ],
        );
      },
    );
  }
}

/// Paints a soft outward glow using layered blurred strokes.
/// The [size] passed to [paint] is LARGER than the child by [glowSpread] on
/// every side, so the rrect is inset by [glowSpread] to sit exactly on the
/// child's border, and the blur bleeds outward.
class _GeminiGlowPainter extends CustomPainter {
  final double rotation;
  final double borderRadius;
  final double glowSpread;
  final bool deepSeekMode;

  // Gemini brand colors — closed loop for a seamless sweep.
  static const _geminiColors = [
    Color(0xFF4285F4), // Blue
    Color(0xFFEA4335), // Red
    Color(0xFFFBBC04), // Yellow
    Color(0xFF34A853), // Green
    Color(0xFF4285F4), // Blue (close loop)
  ];
  static const _geminiStops = [0.0, 0.25, 0.5, 0.75, 1.0];

  // DeepSeek brand colors — pure blue closed loop.
  static const _deepSeekColors = [
    Color(0xFF4D9BFF), // Sky blue
    Color(0xFF1A56DB), // Deep blue
    Color(0xFF00CFFF), // Cyan
    Color(0xFF4D9BFF), // Sky blue (close loop)
  ];
  static const _deepSeekStops = [0.0, 0.33, 0.66, 1.0];

  const _GeminiGlowPainter({
    required this.rotation,
    required this.borderRadius,
    required this.glowSpread,
    this.deepSeekMode = false,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // The rect that coincides with the actual child's outline.
    final childRect = Rect.fromLTWH(
      glowSpread,
      glowSpread,
      size.width - glowSpread * 2,
      size.height - glowSpread * 2,
    );
    final rrect = RRect.fromRectAndRadius(
      childRect,
      Radius.circular(borderRadius),
    );

    final colors = deepSeekMode ? _deepSeekColors : _geminiColors;
    final stops = deepSeekMode ? _deepSeekStops : _geminiStops;
    final shader = SweepGradient(
      colors: colors,
      stops: stops,
      transform: GradientRotation(rotation * 2 * math.pi),
    ).createShader(childRect);

    // Outer glow — wide stroke + strong blur spreads the color outward.
    canvas.drawRRect(
      rrect,
      Paint()
        ..shader = shader
        ..style = PaintingStyle.stroke
        ..strokeWidth = glowSpread * 1.6
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, glowSpread),
    );

    // Inner glow — narrower, less blurred for a crisper halo near the border.
    canvas.drawRRect(
      rrect,
      Paint()
        ..shader = shader
        ..style = PaintingStyle.stroke
        ..strokeWidth = glowSpread * 0.7
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, glowSpread * 0.4),
    );
  }

  @override
  bool shouldRepaint(_GeminiGlowPainter old) =>
      old.rotation != rotation || old.deepSeekMode != deepSeekMode;
}
