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

import '../../../shared/const/app.dart';
import '../../../shared/controllers/theme_controller.dart';
import 'widgets/theme_color_selector_header_delegate.dart';
import 'widgets/topic_selector.dart';
import 'widgets/vertical_panel_view.dart';

// Set the bool flag to true to show debug prints. Even if it is forgotten
// to set it to false, debug prints will not show in release builds.
// The handy part is that if it gets in the way in debugging, it is an easy
// toggle to turn it off there too. Often I just leave them true if it is one
// I want to see in dev mode, unless it is too chatty.
// ignore: no_literal_bool_comparisons, used for debug config.
const bool _debug = !kReleaseMode && false;

/// This is the two topics side-by-side view of the Playground.
///
/// Used only on big desktops, when desktop size is over
/// [App.mediumDesktopWidthBreakpoint] in width.
///
/// This view does not keep the content of the two side-by-side theme
/// topic panels in a [PageView], there is no [PageView] in this layout,
/// it is a lot simpler that way than the `OneOrTwoTopicPageView` view.
/// It is just a [CustomScrollView] with a [SliverPersistentHeader] and the
/// same [ThemeColorSelectorHeaderDelegate] that is used in the large masonry
/// grid view.
///
/// The used [VerticalPanelView]s are identical, they just use different
/// index and have control that selects if the [TopicSelectorVertical]
/// selector should be on the left o right side.
///
/// One advantage with this scroll view is that the two sides scroll
/// independently from each other, not as in the `OneOrTwoTopicPageView`
/// where they are in the same [PageView] and partially scroll together.
class TwoTopicsPage extends StatefulWidget {
  const TwoTopicsPage({
    super.key,
    required this.controller,
  });
  final ThemeController controller;

  @override
  State<TwoTopicsPage> createState() => _TwoTopicsPageState();
}

class _TwoTopicsPageState extends State<TwoTopicsPage>
    with TickerProviderStateMixin {
  late final ScrollController scrollController;
  late int previousSchemeIndex;
  late bool previousUseFlexColorScheme;
  late bool previousUseSubThemes;
  late bool updateDelegate;

  @override
  void initState() {
    super.initState();
    scrollController = ScrollController(
      keepScrollOffset: true,
      debugLabel: 'ThemeTwoTopicsPageScrollController',
    );
    previousSchemeIndex = widget.controller.schemeIndex;
    previousUseFlexColorScheme = widget.controller.useFlexColorScheme;
    previousUseSubThemes = widget.controller.useSubThemes;
    updateDelegate = false;
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    updateDelegate = false;
    if (widget.controller.schemeIndex != previousSchemeIndex) {
      previousSchemeIndex = widget.controller.schemeIndex;
      updateDelegate = true;
    }
    if (widget.controller.useFlexColorScheme != previousUseFlexColorScheme) {
      previousUseFlexColorScheme = widget.controller.useFlexColorScheme;
      updateDelegate = true;
    }
    if (widget.controller.useSubThemes != previousUseSubThemes) {
      previousUseSubThemes = widget.controller.useSubThemes;
      updateDelegate = true;
    }
  }

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

  // The fixed desktop height of the theme selector control,
  // before any margin and media size adjustments
  static const double _kHeightSelector = 118;
  // Magic numbers for normal and dense ListTile
  static const double _kHeightNormaListTile = 52;
  static const double _kHeightDenseListTile = 44;

  @override
  Widget build(BuildContext context) {
    final ThemeController controller = widget.controller;
    final Size mediaSize = MediaQuery.sizeOf(context);
    final EdgeInsets mediaPadding = MediaQuery.paddingOf(context);

    final bool isCompact = widget.controller.compactMode;
    final bool isPinned = mediaSize.height >= App.pinnedSelector;
    final bool isPhone = mediaSize.width < App.phoneWidthBreakpoint ||
        mediaSize.height < App.phoneHeightBreakpoint ||
        isCompact;
    final double phoneReduce = isPhone ? App.colorButtonPhoneReduce : 0;
    final double margins = App.responsiveInsets(mediaSize.width, isCompact);
    // The height diff of the switch = dense - normal.
    final double phoneSwitchReduce =
        isPhone ? _kHeightDenseListTile - _kHeightNormaListTile : 0;
    // The height diff with switches removed.
    final double switchRemove = isCompact ? -_kHeightDenseListTile : 0;
    // All the above is so we can below calculate how high the
    // [ThemeColorSelectorHeaderDelegate] extent should be in different modes,
    // compact and phone responsive layouts.
    final double headerExtent = _kHeightSelector +
        mediaPadding.top +
        margins * 3 +
        phoneReduce +
        phoneSwitchReduce +
        switchRemove;
    // It was tricky to figure out all the extent details, these helped.
    if (_debug) {
      debugPrint('headerExtent ............ : $headerExtent');
      debugPrint('margins ................. : $margins');
      debugPrint('phoneReduce ............. : $phoneReduce');
      debugPrint('kToolbarHeight .......... : $kToolbarHeight');
      debugPrint('media.padding.top ....... : ${mediaPadding.top}');
      debugPrint('media.padding.bottom..... : ${mediaPadding.bottom}');
      debugPrint('media.size.width ........ : ${mediaSize.width}');
      debugPrint('media.size.height ....... : ${mediaSize.height}');
    }
    return CustomScrollView(
      controller: scrollController,
      physics: const ClampingScrollPhysics(),
      slivers: <Widget>[
        SliverPersistentHeader(
          pinned: isPinned,
          floating: true,
          delegate: ThemeColorSelectorHeaderDelegate(
            vsync: this,
            extent: headerExtent,
            controller: controller,
            updateDelegate: updateDelegate,
          ),
        ),
        SliverPadding(
          padding: EdgeInsets.only(top: margins),
          sliver: SliverFillRemaining(
            child: Row(
              children: <Widget>[
                VerticalPanelView(
                  key: const ValueKey<String>('Left Panel'),
                  panel: controller.topicIndexStartSide,
                  onPanelChanged: controller.setTopicIndexStartSide,
                  controller: controller,
                ),
                VerticalPanelView(
                  key: const ValueKey<String>('Right Panel'),
                  isRight: true,
                  panel: controller.topicIndexEndSide,
                  onPanelChanged: controller.setTopicIndexEndSide,
                  controller: controller,
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}
