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

import 'circle_nav_icon_button.dart';

typedef HoverScrollableRowBuilder =
    Widget Function(BuildContext context, ScrollController controller);


class _MouseDragScrollBehavior extends MaterialScrollBehavior {
  const _MouseDragScrollBehavior();

  @override
  Set<PointerDeviceKind> get dragDevices => const {
    PointerDeviceKind.touch,
    PointerDeviceKind.mouse,
    PointerDeviceKind.trackpad,
    PointerDeviceKind.stylus,
  };
}

class HoverScrollableRow extends StatefulWidget {
  final HoverScrollableRowBuilder builder;
  final ScrollController? controller;
  final double scrollFraction;
  final double buttonInset;
  final double iconSize;

  const HoverScrollableRow({
    super.key,
    required this.builder,
    this.controller,
    this.scrollFraction = 0.6,
    this.buttonInset = 10,
    this.iconSize = 26,
  });

  @override
  State<HoverScrollableRow> createState() => _HoverScrollableRowState();
}

class _HoverScrollableRowState extends State<HoverScrollableRow> {
  late ScrollController _controller;
  bool _ownsController = false;
  bool _hovered = false;
  bool _canScrollLeft = false;
  bool _canScrollRight = false;

  @override
  void initState() {
    super.initState();
    _attachController(widget.controller);
    WidgetsBinding.instance.addPostFrameCallback((_) => _updateScrollState());
  }

  @override
  void didUpdateWidget(covariant HoverScrollableRow oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.controller != widget.controller) {
      _detachController();
      _attachController(widget.controller);
      WidgetsBinding.instance.addPostFrameCallback((_) => _updateScrollState());
    }
  }

  void _attachController(ScrollController? external) {
    if (external != null) {
      _controller = external;
      _ownsController = false;
    } else {
      _controller = ScrollController();
      _ownsController = true;
    }
    _controller.addListener(_updateScrollState);
  }

  void _detachController() {
    _controller.removeListener(_updateScrollState);
    if (_ownsController) {
      _controller.dispose();
    }
  }

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

  void _updateScrollState() {
    if (!mounted || !_controller.hasClients) return;
    final maxScroll = _controller.position.maxScrollExtent;
    final offset = _controller.offset;
    final canLeft = offset > 1;
    final canRight = maxScroll - offset > 1;
    if (canLeft != _canScrollLeft || canRight != _canScrollRight) {
      setState(() {
        _canScrollLeft = canLeft;
        _canScrollRight = canRight;
      });
    }
  }

  void _scrollByPage({required bool left}) {
    if (!_controller.hasClients) return;
    final viewport = _controller.position.viewportDimension;
    final delta = viewport * widget.scrollFraction;
    final target = (_controller.offset + (left ? -delta : delta)).clamp(
      0.0,
      _controller.position.maxScrollExtent,
    );
    _controller.animateTo(
      target,
      duration: const Duration(milliseconds: 320),
      curve: Curves.easeOutCubic,
    );
  }

  @override
  Widget build(BuildContext context) {
    final hasOverflow = _canScrollLeft || _canScrollRight;
    final showPager = _hovered && hasOverflow;

    return MouseRegion(
      onEnter: (_) => setState(() => _hovered = true),
      onExit: (_) => setState(() => _hovered = false),
      child: NotificationListener<ScrollMetricsNotification>(
        onNotification: (_) {
          WidgetsBinding.instance.addPostFrameCallback(
            (_) => _updateScrollState(),
          );
          return false;
        },
        child: Stack(
          children: [
            ScrollConfiguration(
              behavior: const _MouseDragScrollBehavior(),
              child: widget.builder(context, _controller),
            ),
            if (hasOverflow)
              Positioned(
                left: widget.buttonInset,
                top: 0,
                bottom: 0,
                child: Center(
                  child: AnimatedOpacity(
                    opacity: showPager ? 1 : 0,
                    duration: const Duration(milliseconds: 140),
                    child: IgnorePointer(
                      ignoring: !showPager || !_canScrollLeft,
                      child: CircleNavIconButton(
                        icon: Icons.chevron_left_rounded,
                        iconSize: widget.iconSize,
                        enabled: _canScrollLeft,
                        onPressed: _canScrollLeft
                            ? () => _scrollByPage(left: true)
                            : null,
                      ),
                    ),
                  ),
                ),
              ),
            if (hasOverflow)
              Positioned(
                right: widget.buttonInset,
                top: 0,
                bottom: 0,
                child: Center(
                  child: AnimatedOpacity(
                    opacity: showPager ? 1 : 0,
                    duration: const Duration(milliseconds: 140),
                    child: IgnorePointer(
                      ignoring: !showPager || !_canScrollRight,
                      child: CircleNavIconButton(
                        icon: Icons.chevron_right_rounded,
                        iconSize: widget.iconSize,
                        enabled: _canScrollRight,
                        onPressed: _canScrollRight
                            ? () => _scrollByPage(left: false)
                            : null,
                      ),
                    ),
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}
