content: import 'dart:async';
  import 'dart:ui';
  
  import 'package:flutter/material.dart';
  
  import '../../../../shared/const/app.dart';
  import '../../../../shared/utils/app_scroll_behavior.dart';
  import '../../../../shared/utils/colors_are_close.dart';
  import '../model/theme_topic.dart';
  
  // ignore_for_file: comment_references
  
  /// Horizontal panel selector of active theme topic to view.
  ///
  /// Used in phone, tablet, small and medium desktop view.
  class TopicSelectorHorizontal extends StatefulWidget {
    const TopicSelectorHorizontal({
      super.key,
      required this.page,
      required this.onSelect,
      required this.isCompact,
      required this.buttonWidth,
    });
    final int page;
    final ValueChanged<int> onSelect;
    final bool isCompact;
    final double buttonWidth;
  
    @override
    State<TopicSelectorHorizontal> createState() =>
        _TopicSelectorHorizontalState();
  }
  
  class _TopicSelectorHorizontalState extends State<TopicSelectorHorizontal> {
    late final ScrollController scrollController;
    late int selectedPage;
    late double scrollOffset;
    late double buttonWidth;
  
    @override
    void initState() {
      super.initState();
      selectedPage = widget.page;
      scrollOffset = widget.buttonWidth * selectedPage;
      scrollController = ScrollController(
        keepScrollOffset: true,
        initialScrollOffset: scrollOffset,
        debugLabel: 'Horizontal topic selector',
      );
    }
  
    @override
    void dispose() {
      scrollController.dispose();
      super.dispose();
    }
  
    @override
    void didUpdateWidget(covariant TopicSelectorHorizontal oldWidget) {
      super.didUpdateWidget(oldWidget);
  
      if (selectedPage != widget.page) {
        selectedPage = widget.page;
        scrollOffset = widget.buttonWidth * selectedPage;
        unawaited(scrollController.animateTo(scrollOffset,
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeOutCubic));
      }
    }
  
    @override
    Widget build(BuildContext context) {
      final Size mediaSize = MediaQuery.sizeOf(context);
      final EdgeInsets mediaPadding = MediaQuery.paddingOf(context);
      final bool isPhone = mediaSize.width < App.phoneWidthBreakpoint ||
          mediaSize.height < App.phoneHeightBreakpoint ||
          widget.isCompact;
      final double margins =
          App.responsiveInsets(mediaSize.width, widget.isCompact);
      final double effectiveHeight = App.panelButtonHeight +
          margins * 2 +
          (isPhone ? App.panelButtonPhoneHeightReduce : 0);
      final double topPadding = mediaPadding.top;
      final double buttonHorizontalMargin = isPhone ? 2 : 4;
  
      return FocusTraversalGroup(
        child: Material(
          color: Theme.of(context).colorScheme.surfaceTint.withAlpha(0x38),
          child: ClipRect(
            child: BackdropFilter(
              filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
              child: Padding(
                padding:
                    EdgeInsets.only(top: topPadding + margins, bottom: margins),
                child: SizedBox(
                  height: effectiveHeight - margins,
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: ScrollConfiguration(
                          behavior: const DragScrollBehavior(),
                          child: ListView.builder(
                            padding: EdgeInsets.symmetric(
                              horizontal: margins - buttonHorizontalMargin,
                            ),
                            controller: scrollController,
                            primary: false,
                            physics: const ClampingScrollPhysics(),
                            scrollDirection: Axis.horizontal,
                            itemCount: themeTopics.length,
                            itemBuilder: (BuildContext context, int index) {
                              return _TopicButton(
                                item: themeTopics[index],
                                onSelect: () {
                                  widget.onSelect(index);
                                  setState(() {
                                    selectedPage = index;
                                  });
                                },
                                selected: selectedPage == index,
                                isCompact: widget.isCompact,
                                width: widget.buttonWidth,
                                buttonHorizontalMargin: buttonHorizontalMargin,
                              );
                            },
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      );
    }
  }
  
  /// Vertical theme topic selector used in the two columns view.
  ///
  /// Used only on desktop views via [TwoTopicsPage] and
  /// [TwoTopicsVerticalPage].
  class TopicSelectorVertical extends StatefulWidget {
    const TopicSelectorVertical({
      super.key,
      required this.page,
      required this.onSelect,
      required this.isCompact,
      this.isRight = false,
      this.addTopPadding = false,
    });
    final int page;
    final ValueChanged<int> onSelect;
    final bool isCompact;
    final bool isRight;
    final bool addTopPadding;
  
    @override
    State<TopicSelectorVertical> createState() => _TopicSelectorVerticalState();
  }
  
  class _TopicSelectorVerticalState extends State<TopicSelectorVertical> {
    late final ScrollController scrollController;
    late int selectedPage;
    late double scrollOffset;
  
    static const double buttonWidth =
        App.panelButtonWidth + App.panelButtonPhoneWidthReduce - 4;
    static const double buttonHeight = App.panelButtonHeight +
        App.edgeInsetsPhone * 2 +
        App.panelButtonPhoneHeightReduce -
        12;
    static const double buttonMargin = 4;
  
    static const double heightReduce = 10;
    static const double widthReduce = 14;
  
    @override
    void initState() {
      super.initState();
      selectedPage = widget.page;
      final double compactHeight = widget.isCompact ? heightReduce : 0;
      scrollOffset = (buttonHeight - compactHeight) * selectedPage;
      scrollController = ScrollController(
        keepScrollOffset: true,
        initialScrollOffset: scrollOffset,
        debugLabel: widget.isRight ? 'Right v topics' : 'Left v topics',
      );
    }
  
    @override
    void dispose() {
      scrollController.dispose();
      super.dispose();
    }
  
    @override
    void didUpdateWidget(covariant TopicSelectorVertical oldWidget) {
      super.didUpdateWidget(oldWidget);
      if (selectedPage != widget.page) {
        selectedPage = widget.page;
        final double compactHeight = widget.isCompact ? heightReduce : 0;
        scrollOffset = (buttonHeight - compactHeight) * selectedPage;
        scrollOffset = buttonHeight * selectedPage;
        unawaited(scrollController.animateTo(scrollOffset,
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeOutCubic));
      }
    }
  
    @override
    Widget build(BuildContext context) {
      final Size mediaSize = MediaQuery.sizeOf(context);
      final EdgeInsets mediaPadding = MediaQuery.paddingOf(context);
      final double margins =
          App.responsiveInsets(mediaSize.width, widget.isCompact);
      final double topPadding =
          widget.addTopPadding ? mediaPadding.top + margins : 0;
      final double compactWidth = widget.isCompact ? widthReduce : 0;
      final double compactHeight = widget.isCompact ? heightReduce : 0;
  
      return FocusTraversalGroup(
        child: ConstrainedBox(
          constraints: BoxConstraints.tightFor(
              width: buttonWidth + margins - compactWidth),
          child: ScrollConfiguration(
            behavior: const DragScrollBehavior(),
            child: ListView.builder(
              padding: EdgeInsets.only(
                left: widget.isRight ? 0 : margins - buttonMargin,
                right: widget.isRight ? margins - buttonMargin : 0,
                top: topPadding,
                bottom: margins,
              ),
              controller: scrollController,
              primary: false,
              physics: const ClampingScrollPhysics(),
              itemCount: themeTopics.length,
              itemBuilder: (BuildContext context, int index) {
                return Padding(
                  padding: const EdgeInsets.only(bottom: buttonMargin),
                  child: SizedBox(
                    height: buttonHeight - buttonMargin - compactHeight,
                    child: _TopicButton(
                      item: themeTopics[index],
                      onSelect: () {
                        widget.onSelect(index);
                        setState(() {
                          selectedPage = index;
                        });
                      },
                      selected: selectedPage == index,
                      isCompact: true,
                      isSmall: widget.isCompact,
                      width: buttonWidth - compactWidth,
                      buttonHorizontalMargin: buttonMargin,
                    ),
                  ),
                );
              },
            ),
          ),
        ),
      );
    }
  }
  
  /// A button with [Topic] button label and icon.
  class _TopicButton extends StatefulWidget {
    const _TopicButton({
      required this.item,
      required this.selected,
      required this.onSelect,
      required this.isCompact,
      this.isSmall,
      required this.width,
      this.buttonHorizontalMargin = 4,
    });
    final Topic item;
    final bool selected;
    final VoidCallback onSelect;
    final bool isCompact;
    final bool? isSmall;
    final double width;
    final double buttonHorizontalMargin;
  
    @override
    State<_TopicButton> createState() => _TopicButtonState();
  }
  
  class _TopicButtonState extends State<_TopicButton> {
    late final FocusNode _focusNode;
  
    @override
    void initState() {
      super.initState();
      _focusNode = FocusNode();
    }
  
    @override
    void dispose() {
      _focusNode.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      final Size mediaSize = MediaQuery.sizeOf(context);
      final bool isPhoneSize = mediaSize.width < App.phoneWidthBreakpoint ||
          mediaSize.height < App.phoneHeightBreakpoint;
      final bool isPhone = isPhoneSize || widget.isCompact;
      final double textSize = isPhoneSize || widget.isCompact
          ? widget.isSmall ?? false
              ? 8
              : 10
          : 11;
      final double iconSize = isPhoneSize || widget.isCompact
          ? widget.isSmall ?? false
              ? 24
              : 28
          : 45;
      final double borderWidth = isPhone ? 3 : 5;
      final double verticalPadding = isPhone ? 6 : 10;
      final ThemeData theme = Theme.of(context);
      final bool useMaterial3 = theme.useMaterial3;
      final ColorScheme scheme = theme.colorScheme;
      final Color cardColor = theme.cardColor;
      final Color scaffoldBackground = theme.scaffoldBackgroundColor;
      final bool isLight = theme.brightness == Brightness.light;
      final Color background =
          isLight ? scheme.surfaceContainerLow : scheme.surfaceContainerHigh;
      final Color iconColor =
          widget.item.group.color(context); //_onColor(background);
      final Color textColor = theme.colorScheme.onSurface.withAlpha(0xCC);
      final Color unselectedColor =
          colorsAreClose(background, scaffoldBackground, isLight) ||
                  colorsAreClose(cardColor, scaffoldBackground, isLight)
              ? theme.dividerColor
              : Colors.transparent;
  
      // Get the card's ShapeBorder from the theme card shape
      ShapeBorder? shapeBorder = theme.cardTheme.shape;
      // Make a shape border if our background color is close in color
      // to the scaffold background color, because if that happens we want to
      // separate it from the background with a border.
      // If we had one shape, copy in a border side to it.
      if (shapeBorder is RoundedRectangleBorder) {
        shapeBorder = shapeBorder.copyWith(
          side: widget.selected
              ? BorderSide(color: iconColor, width: borderWidth)
              : BorderSide(color: unselectedColor),
        );
      } else {
        // If border was null, make one matching Card default, but with a
        // BorderSide, if it was not null, we leave it as it was, it means it
        // has some other preexisting ShapeBorder, but it was not a
        // RoundedRectangleBorder, we don't know what it was, just let it be.
        shapeBorder ??= RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(useMaterial3 ? 12 : 4)),
          side: widget.selected
              ? BorderSide(color: iconColor, width: borderWidth)
              : BorderSide(color: unselectedColor),
        );
      }
      return SizedBox(
        width: widget.width,
        child: Card(
          elevation: 0,
          clipBehavior: Clip.antiAlias,
          margin: EdgeInsets.symmetric(horizontal: widget.buttonHorizontalMargin),
          color: background,
          shape: shapeBorder,
          child: InkWell(
            focusNode: _focusNode,
            onTap: () {
              _focusNode.requestFocus();
              widget.onSelect.call();
            },
            child: Padding(
              padding: EdgeInsets.symmetric(vertical: verticalPadding),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  if (widget.item.iconTurns == 0)
                    Icon(
                      widget.item.icon,
                      size: iconSize,
                      color: iconColor,
                    )
                  else
                    RotatedBox(
                      quarterTurns: widget.item.iconTurns,
                      child: Icon(
                        widget.item.icon,
                        size: iconSize,
                        color: iconColor,
                      ),
                    ),
                  Text(
                    widget.item.buttonLabel,
                    style: theme.textTheme.labelSmall!.copyWith(
                      color: textColor,
                      fontSize: textSize,
                    ),
                    textAlign: TextAlign.center,
                  ),
                ],
              ),
            ),
          ),
        ),
      );
    }
  }
  