import 'dart:async';

import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:kasy_kit/core/haptics/haptic_feedback_notifier.dart';
import 'package:kasy_kit/core/theme/theme.dart';

/// Universal hover/press wrapper — works on any widget shape.
///
/// Native: animated background fill on press + haptic (no Material ripple).
/// The pressed state lasts at least [_kMinPressDuration] so it is visible
/// even on quick taps.
///
/// Web: pointer cursor + subtle background on hover, slightly darker on press.
///
/// Contrast with [KasyPressableDepth]: this component uses a background fill
/// while [KasyPressableDepth] uses a scale animation. Use this one for
/// surfaces that already have their own shape (list rows, cards, menu items,
/// custom buttons); use [KasyPressableDepth] when you want a "push-in" feel.
class KasyHover extends ConsumerStatefulWidget {
  const KasyHover({
    super.key,
    required this.child,
    required this.onTap,
    this.padding,
    this.borderRadius = BorderRadius.zero,
    this.margin,
    this.semanticLabel,
    this.hapticEnabled = true,
    this.pressColor,
  });

  final Widget child;
  final VoidCallback onTap;

  /// Internal padding (rendered inside the feedback overlay area).
  final EdgeInsetsGeometry? padding;

  /// Corner radius of the feedback overlay. Match the value of the parent
  /// container so the pressed fill does not bleed outside the rounded shape.
  final BorderRadius borderRadius;

  /// External spacing (not covered by the feedback overlay).
  final EdgeInsetsGeometry? margin;

  /// Accessibility label for TalkBack / VoiceOver.
  final String? semanticLabel;

  /// Haptic on tap (automatically ignored on web).
  final bool hapticEnabled;

  /// Tint color for the hover/press overlay.
  ///
  /// When null, falls back to [ColorScheme.onSurface] — a neutral dark/light
  /// overlay suited for plain surfaces.
  ///
  /// Pass the surface's accent color (e.g. [KasyColors.primary]) when the
  /// background is already tinted so the feedback stays on-palette and avoids
  /// a mismatched gray cast (e.g. a primary-tinted button should deepen with
  /// primary, not darken with neutral gray).
  final Color? pressColor;

  @override
  ConsumerState<KasyHover> createState() => _KasyHoverState();
}

class _KasyHoverState extends ConsumerState<KasyHover> {
  // Minimum duration the pressed background stays visible — prevents an
  // imperceptible flash on very quick taps.
  static const Duration _kMinPressDuration = Duration(milliseconds: 160);

  bool _hovered = false;
  bool _pressed = false;
  Timer? _releaseTimer;

  @override
  void dispose() {
    _releaseTimer?.cancel();
    super.dispose();
  }

  Color _overlayColor(BuildContext context) {
    final bool isDark = Theme.of(context).brightness == Brightness.dark;
    final Color base = widget.pressColor ?? context.colors.onSurface;
    if (_pressed) return base.withValues(alpha: isDark ? 0.04 : 0.10);
    if (_hovered) return base.withValues(alpha: isDark ? 0.02 : 0.06);
    return Colors.transparent;
  }

  void _onTapDown(TapDownDetails _) {
    _releaseTimer?.cancel();
    setState(() => _pressed = true);
  }

  void _onTapUp(TapUpDetails _) {
    // Release is controlled by the timer in _handleTap so the pressed
    // state is always visible for at least _kMinPressDuration.
  }

  void _onTapCancel() {
    _releaseTimer?.cancel();
    setState(() => _pressed = false);
  }

  void _handleTap() {
    if (widget.hapticEnabled && !kIsWeb && ref.read(hapticFeedbackProvider)) {
      HapticFeedback.selectionClick();
    }
    widget.onTap();
    _releaseTimer = Timer(_kMinPressDuration, () {
      if (mounted) setState(() => _pressed = false);
    });
  }

  @override
  Widget build(BuildContext context) {
    final Widget content = AnimatedContainer(
      duration: const Duration(milliseconds: 120),
      curve: Curves.easeOut,
      decoration: BoxDecoration(
        color: _overlayColor(context),
        borderRadius: widget.borderRadius,
      ),
      padding: widget.padding,
      child: widget.child,
    );

    Widget interactive = GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: _handleTap,
      onTapDown: _onTapDown,
      onTapUp: _onTapUp,
      onTapCancel: _onTapCancel,
      child: content,
    );

    if (kIsWeb) {
      interactive = MouseRegion(
        cursor: SystemMouseCursors.click,
        onEnter: (_) => setState(() => _hovered = true),
        onExit: (_) {
          setState(() {
            _hovered = false;
            _pressed = false;
          });
        },
        child: interactive,
      );
    }

    if (widget.semanticLabel != null) {
      interactive = Semantics(
        button: true,
        label: widget.semanticLabel,
        child: interactive,
      );
    }

    if (widget.margin != null) {
      return Padding(padding: widget.margin!, child: interactive);
    }
    return interactive;
  }
}
