// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

/// Renders Backlog board controls for the FocusFlow Flutter UI.
library;

import 'dart:async';

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

import '../../controllers/backlog_board_controller.dart';
import '../../theme/backlog_board_visual_tokens.dart';
import '../../theme/focus_flow_tokens.dart';

/// Header controls for Compact/Board mode and settings.
class BacklogModeAndSettingsControls extends StatelessWidget {
  /// Creates mode and settings controls.
  const BacklogModeAndSettingsControls({super.key});

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          height: 42,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: FocusFlowTokens.subtleBorder),
          ),
          child: Row(
            children: const [
              _ModeSegment(label: 'Compact', active: false),
              _ModeSegment(label: 'Board', active: true),
            ],
          ),
        ),
        const SizedBox(width: 18),
        OutlinedButton.icon(
          onPressed: () {},
          icon: const Icon(Icons.wb_sunny_outlined, size: 18),
          label: const Text('Settings'),
          style: OutlinedButton.styleFrom(
            fixedSize: const Size(122, 42),
            foregroundColor: FocusFlowTokens.textPrimary,
            side: const BorderSide(color: FocusFlowTokens.subtleBorder),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(8),
            ),
          ),
        ),
      ],
    );
  }
}

/// Search, filter, sort, group, and new-task controls.
class BacklogBoardTopControls extends StatefulWidget {
  /// Creates Backlog board top controls.
  const BacklogBoardTopControls({
    required this.controller,
    required this.onNewTask,
    super.key,
  });

  /// Controller updated by shell controls.
  final BacklogBoardController controller;

  /// Callback invoked by the New Task button.
  final VoidCallback? onNewTask;

  /// Creates the mutable state object used by this stateful widget.
  /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
  @override
  State<BacklogBoardTopControls> createState() =>
      _BacklogBoardTopControlsState();
}

/// State for Backlog board top controls.
class _BacklogBoardTopControlsState extends State<BacklogBoardTopControls> {
  /// Text controller for the search field.
  late final TextEditingController _searchController;

  /// Initializes text controller state from the current board controller.
  @override
  void initState() {
    super.initState();
    _searchController = TextEditingController(
      text: widget.controller.searchText ?? '',
    );
  }

  /// Releases text controller resources.
  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    final activeFilterCount =
        widget.controller.filters.length +
        widget.controller.boardFilters.activeFilterCount;
    final searchText = widget.controller.searchText ?? '';
    if (searchText.isEmpty && _searchController.text.isNotEmpty) {
      _searchController.clear();
    }
    return Row(
      children: [
        Expanded(
          child: SizedBox(
            height: 44,
            child: TextField(
              key: const ValueKey('backlog-search-field'),
              controller: _searchController,
              onChanged: (value) {
                unawaited(widget.controller.updateSearchText(value));
              },
              style: const TextStyle(color: FocusFlowTokens.textPrimary),
              decoration: InputDecoration(
                prefixIcon: const Icon(
                  Icons.search,
                  color: FocusFlowTokens.textMuted,
                ),
                suffixIcon: searchText.isEmpty
                    ? null
                    : IconButton(
                        key: const ValueKey('backlog-search-clear'),
                        tooltip: 'Clear search',
                        onPressed: () {
                          _searchController.clear();
                          unawaited(widget.controller.updateSearchText(null));
                        },
                        icon: const Icon(
                          Icons.close,
                          color: FocusFlowTokens.textMuted,
                        ),
                      ),
                hintText: 'Search backlog...',
                hintStyle: const TextStyle(color: FocusFlowTokens.textFaint),
                filled: true,
                fillColor: FocusFlowTokens.panelBackground,
                contentPadding: EdgeInsets.zero,
                enabledBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(8),
                  borderSide: const BorderSide(
                    color: FocusFlowTokens.subtleBorder,
                  ),
                ),
                focusedBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(8),
                  borderSide: const BorderSide(
                    color: FocusFlowTokens.accentMagenta,
                  ),
                ),
              ),
            ),
          ),
        ),
        const SizedBox(width: 16),
        _BacklogControlButton(
          key: const ValueKey('backlog-filter-button'),
          icon: Icons.filter_alt_outlined,
          label: activeFilterCount == 0
              ? 'Filters'
              : 'Filters $activeFilterCount',
          onPressed: () {
            unawaited(_showFilterDialog(context, widget.controller));
          },
        ),
        const SizedBox(width: 14),
        _BacklogMenuControlButton<BacklogSortKey>(
          key: const ValueKey('backlog-sort-menu-button'),
          icon: Icons.tune,
          label: 'Sort: ${_sortLabel(widget.controller.sortKey)}',
          width: 158,
          selectedValue: widget.controller.sortKey,
          options: _sortOptions,
          onSelected: (value) {
            unawaited(widget.controller.updateSortKey(value));
          },
        ),
        const SizedBox(width: 14),
        _BacklogMenuControlButton<BacklogBoardGroupMode>(
          key: const ValueKey('backlog-group-menu-button'),
          icon: Icons.dashboard_customize_outlined,
          label: 'Group: ${_groupLabel(widget.controller.groupMode)}',
          width: 156,
          selectedValue: widget.controller.groupMode,
          options: _groupOptions,
          onSelected: (value) {
            unawaited(widget.controller.updateGroupMode(value));
          },
        ),
        const SizedBox(width: 18),
        FilledButton(
          key: const ValueKey('backlog-new-task-button'),
          onPressed: widget.onNewTask,
          style: FilledButton.styleFrom(
            fixedSize: const Size(146, 44),
            padding: EdgeInsets.zero,
            backgroundColor: FocusFlowTokens.accentMagenta,
            foregroundColor: FocusFlowTokens.textPrimary,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(8),
            ),
          ),
          child: const FittedBox(
            fit: BoxFit.scaleDown,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Icon(Icons.add, size: 18),
                SizedBox(width: 8),
                Text('New Task'),
                SizedBox(width: 4),
                Icon(Icons.keyboard_arrow_down, size: 18),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

/// One segment in the Backlog mode toggle.
class _ModeSegment extends StatelessWidget {
  /// Creates a mode segment.
  const _ModeSegment({required this.label, required this.active});

  /// Segment label.
  final String label;

  /// Whether this segment is selected.
  final bool active;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 78,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        color: active ? FocusFlowTokens.glassPanelStrong : Colors.transparent,
        borderRadius: BorderRadius.circular(8),
        border: active
            ? Border.all(color: FocusFlowTokens.navBorder)
            : Border.all(color: Colors.transparent),
      ),
      child: Text(
        label,
        style: TextStyle(
          color: active
              ? FocusFlowTokens.accentMagenta
              : FocusFlowTokens.textPrimary,
          fontSize: 13,
          fontWeight: FontWeight.w700,
        ),
      ),
    );
  }
}

/// Compact outlined control button used by the Backlog shell.
class _BacklogControlButton extends StatelessWidget {
  /// Creates a Backlog control button.
  const _BacklogControlButton({
    required this.icon,
    required this.label,
    required this.onPressed,
    super.key,
  });

  /// Leading icon for the control.
  final IconData icon;

  /// Control label.
  final String label;

  /// Callback invoked when the control is pressed.
  final VoidCallback onPressed;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return OutlinedButton.icon(
      onPressed: onPressed,
      icon: Icon(icon, size: 18),
      label: Text(label),
      style: OutlinedButton.styleFrom(
        fixedSize: const Size(132, 44),
        foregroundColor: FocusFlowTokens.textPrimary,
        side: const BorderSide(color: FocusFlowTokens.subtleBorder),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
      ),
    );
  }
}

/// Generic popup menu button styled like the Backlog control row.
class _BacklogMenuControlButton<T> extends StatelessWidget {
  /// Creates a popup menu control.
  const _BacklogMenuControlButton({
    required this.icon,
    required this.label,
    required this.width,
    required this.selectedValue,
    required this.options,
    required this.onSelected,
    super.key,
  });

  /// Leading icon for the control.
  final IconData icon;

  /// Button label.
  final String label;

  /// Fixed button width.
  final double width;

  /// Currently selected value.
  final T selectedValue;

  /// Menu options.
  final List<_MenuOption<T>> options;

  /// Selection callback.
  final ValueChanged<T> onSelected;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<T>(
      color: FocusFlowTokens.elevatedPanel,
      onSelected: onSelected,
      itemBuilder: (context) {
        return [
          for (final option in options)
            PopupMenuItem<T>(
              value: option.value,
              child: Row(
                children: [
                  Icon(
                    option.value == selectedValue
                        ? Icons.check
                        : Icons.circle_outlined,
                    size: 16,
                    color: option.value == selectedValue
                        ? FocusFlowTokens.accentMagenta
                        : FocusFlowTokens.textFaint,
                  ),
                  const SizedBox(width: 10),
                  Text(
                    option.label,
                    style: const TextStyle(color: FocusFlowTokens.textPrimary),
                  ),
                ],
              ),
            ),
        ];
      },
      child: Container(
        width: width,
        height: 44,
        padding: const EdgeInsets.symmetric(horizontal: 14),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: FocusFlowTokens.subtleBorder),
        ),
        child: Row(
          children: [
            Icon(icon, size: 18, color: FocusFlowTokens.textPrimary),
            const SizedBox(width: 9),
            Expanded(
              child: Text(
                label,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
                style: const TextStyle(
                  color: FocusFlowTokens.textPrimary,
                  fontSize: 13,
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
            const SizedBox(width: 6),
            const Icon(
              Icons.keyboard_arrow_down,
              color: FocusFlowTokens.textMuted,
              size: 18,
            ),
          ],
        ),
      ),
    );
  }
}

/// Menu option for a Backlog popup control.
class _MenuOption<T> {
  /// Creates a menu option.
  const _MenuOption({required this.value, required this.label});

  /// Option value.
  final T value;

  /// Display label.
  final String label;
}

/// Result returned from the filter dialog.
class _FilterDialogResult {
  /// Creates a filter dialog result.
  _FilterDialogResult({
    required List<BacklogFilter> legacyFilters,
    required this.boardFilters,
  }) : legacyFilters = List<BacklogFilter>.unmodifiable(legacyFilters);

  /// Legacy backlog filters to apply.
  final List<BacklogFilter> legacyFilters;

  /// Board-specific filters to apply.
  final BacklogBoardFilterSelection boardFilters;
}

/// Dialog for editing Backlog board filters.
class _BacklogFilterDialog extends StatefulWidget {
  /// Creates a Backlog filter dialog.
  const _BacklogFilterDialog({
    required this.initialLegacyFilters,
    required this.initialBoardFilters,
    required this.projectOptions,
  });

  /// Legacy filters active before the dialog opened.
  final List<BacklogFilter> initialLegacyFilters;

  /// Board filters active before the dialog opened.
  final BacklogBoardFilterSelection initialBoardFilters;

  /// Project options available to the board.
  final List<ProjectOptionReadModel> projectOptions;

  /// Creates the mutable state object used by this stateful widget.
  /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
  @override
  State<_BacklogFilterDialog> createState() => _BacklogFilterDialogState();
}

/// State for the Backlog filter dialog.
class _BacklogFilterDialogState extends State<_BacklogFilterDialog> {
  /// Selected priority groups.
  late Set<BacklogBoardPriorityFilter> _priorityGroups;

  /// Selected project ids.
  late Set<String> _projectIds;

  /// Selected duration buckets.
  late Set<BacklogBoardDurationFilter> _durationBuckets;

  /// Selected board buckets.
  late Set<BacklogBoardBucket> _buckets;

  /// Whether missing-duration tasks are selected.
  late bool _missingDurationOnly;

  /// Whether no-reward tasks are selected.
  late bool _noRewardSetOnly;

  /// Initializes mutable filter selections.
  @override
  void initState() {
    super.initState();
    _priorityGroups = {...widget.initialBoardFilters.priorityGroups};
    _projectIds = {...widget.initialBoardFilters.projectIds};
    _durationBuckets = {...widget.initialBoardFilters.durationBuckets};
    _buckets = {...widget.initialBoardFilters.buckets};
    _missingDurationOnly = widget.initialBoardFilters.missingDurationOnly;
    _noRewardSetOnly = widget.initialLegacyFilters.contains(
      BacklogFilter.noRewardSet,
    );
  }

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Dialog(
      backgroundColor: FocusFlowTokens.elevatedPanel,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
        side: const BorderSide(color: FocusFlowTokens.subtleBorder),
      ),
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: 560, maxHeight: 680),
        child: Padding(
          padding: const EdgeInsets.fromLTRB(22, 20, 22, 16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const Row(
                children: [
                  Icon(
                    Icons.filter_alt_outlined,
                    color: FocusFlowTokens.accentMagenta,
                  ),
                  SizedBox(width: 10),
                  Expanded(
                    child: Text(
                      'Filters',
                      style: TextStyle(
                        color: FocusFlowTokens.textPrimary,
                        fontSize: 20,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      _FilterSection(
                        title: 'Priority',
                        children: [
                          _checkbox(
                            label: 'High priority',
                            value: _priorityGroups.contains(
                              BacklogBoardPriorityFilter.high,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _priorityGroups,
                                BacklogBoardPriorityFilter.high,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: 'Medium priority',
                            value: _priorityGroups.contains(
                              BacklogBoardPriorityFilter.medium,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _priorityGroups,
                                BacklogBoardPriorityFilter.medium,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: 'Low priority',
                            value: _priorityGroups.contains(
                              BacklogBoardPriorityFilter.low,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _priorityGroups,
                                BacklogBoardPriorityFilter.low,
                                value,
                              );
                            },
                          ),
                        ],
                      ),
                      _FilterSection(
                        title: 'Project',
                        children: widget.projectOptions.isEmpty
                            ? const [
                                Padding(
                                  padding: EdgeInsets.symmetric(vertical: 8),
                                  child: Text(
                                    'No projects loaded',
                                    style: TextStyle(
                                      color: FocusFlowTokens.textMuted,
                                    ),
                                  ),
                                ),
                              ]
                            : [
                                for (final project in widget.projectOptions)
                                  _checkbox(
                                    label: project.name,
                                    dotColor:
                                        BacklogBoardVisualTokens.projectColor(
                                          project.colorToken,
                                        ),
                                    value: _projectIds.contains(
                                      project.projectId,
                                    ),
                                    onChanged: (value) {
                                      _toggleSet(
                                        _projectIds,
                                        project.projectId,
                                        value,
                                      );
                                    },
                                  ),
                              ],
                      ),
                      _FilterSection(
                        title: 'Duration',
                        children: [
                          _checkbox(
                            label: '0-30 min',
                            value: _durationBuckets.contains(
                              BacklogBoardDurationFilter.zeroToThirty,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _durationBuckets,
                                BacklogBoardDurationFilter.zeroToThirty,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: '31-60 min',
                            value: _durationBuckets.contains(
                              BacklogBoardDurationFilter.thirtyToSixty,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _durationBuckets,
                                BacklogBoardDurationFilter.thirtyToSixty,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: '61-120 min',
                            value: _durationBuckets.contains(
                              BacklogBoardDurationFilter.sixtyToOneTwenty,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _durationBuckets,
                                BacklogBoardDurationFilter.sixtyToOneTwenty,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: '120+ min',
                            value: _durationBuckets.contains(
                              BacklogBoardDurationFilter.overOneTwenty,
                            ),
                            onChanged: (value) {
                              _toggleSet(
                                _durationBuckets,
                                BacklogBoardDurationFilter.overOneTwenty,
                                value,
                              );
                            },
                          ),
                          _checkbox(
                            label: 'Missing duration',
                            value: _missingDurationOnly,
                            onChanged: (value) {
                              setState(() {
                                _missingDurationOnly = value;
                              });
                            },
                          ),
                        ],
                      ),
                      _FilterSection(
                        title: 'Column',
                        children: [
                          for (final bucket in BacklogBoardBucket.values)
                            _checkbox(
                              label: _bucketLabel(bucket),
                              dotColor: BacklogBoardVisualTokens.bucketAccent(
                                bucket,
                              ),
                              value: _buckets.contains(bucket),
                              onChanged: (value) {
                                _toggleSet(_buckets, bucket, value);
                              },
                            ),
                        ],
                      ),
                      _FilterSection(
                        title: 'Cleanup',
                        children: [
                          _checkbox(
                            label: 'No reward set',
                            value: _noRewardSetOnly,
                            onChanged: (value) {
                              setState(() {
                                _noRewardSetOnly = value;
                              });
                            },
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Row(
                children: [
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop(
                        _FilterDialogResult(
                          legacyFilters: const [],
                          boardFilters:
                              const BacklogBoardFilterSelection.empty(),
                        ),
                      );
                    },
                    child: const Text('Clear'),
                  ),
                  const Spacer(),
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: const Text('Cancel'),
                  ),
                  const SizedBox(width: 8),
                  FilledButton(
                    onPressed: () {
                      Navigator.of(context).pop(_result());
                    },
                    style: FilledButton.styleFrom(
                      backgroundColor: FocusFlowTokens.accentMagenta,
                      foregroundColor: FocusFlowTokens.textPrimary,
                    ),
                    child: const Text('Apply'),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  /// Builds a styled filter checkbox row.
  Widget _checkbox({
    required String label,
    required bool value,
    required ValueChanged<bool> onChanged,
    Color? dotColor,
  }) {
    return Material(
      type: MaterialType.transparency,
      child: CheckboxListTile(
        dense: true,
        value: value,
        onChanged: (next) {
          onChanged(next ?? false);
        },
        controlAffinity: ListTileControlAffinity.leading,
        activeColor: FocusFlowTokens.accentMagenta,
        checkColor: FocusFlowTokens.textPrimary,
        contentPadding: EdgeInsets.zero,
        title: Row(
          children: [
            if (dotColor != null) ...[
              Container(
                width: 8,
                height: 8,
                decoration: BoxDecoration(
                  color: dotColor,
                  shape: BoxShape.circle,
                ),
              ),
              const SizedBox(width: 8),
            ],
            Expanded(
              child: Text(
                label,
                style: const TextStyle(color: FocusFlowTokens.textPrimary),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// Toggles [value] in [set] and rebuilds the dialog.
  void _toggleSet<T>(Set<T> set, T value, bool selected) {
    setState(() {
      if (selected) {
        set.add(value);
      } else {
        set.remove(value);
      }
    });
  }

  /// Builds the immutable result for the current dialog selections.
  _FilterDialogResult _result() {
    return _FilterDialogResult(
      legacyFilters: [if (_noRewardSetOnly) BacklogFilter.noRewardSet],
      boardFilters: BacklogBoardFilterSelection(
        priorityGroups: _priorityGroups,
        projectIds: _projectIds,
        durationBuckets: _durationBuckets,
        buckets: _buckets,
        missingDurationOnly: _missingDurationOnly,
      ),
    );
  }
}

/// Section wrapper inside the filter dialog.
class _FilterSection extends StatelessWidget {
  /// Creates a filter section.
  const _FilterSection({required this.title, required this.children});

  /// Section title.
  final String title;

  /// Section children.
  final List<Widget> children;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: DecoratedBox(
        decoration: BoxDecoration(
          color: FocusFlowTokens.panelBackground.withValues(alpha: 0.72),
          borderRadius: BorderRadius.circular(8),
          border: Border.all(
            color: FocusFlowTokens.subtleBorder.withValues(alpha: 0.72),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.fromLTRB(14, 12, 14, 10),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Text(
                title,
                style: const TextStyle(
                  color: FocusFlowTokens.textPrimary,
                  fontWeight: FontWeight.w800,
                ),
              ),
              const SizedBox(height: 6),
              ...children,
            ],
          ),
        ),
      ),
    );
  }
}

/// Opens the filter dialog and applies the returned result.
Future<void> _showFilterDialog(
  BuildContext context,
  BacklogBoardController controller,
) async {
  final result = await showDialog<_FilterDialogResult>(
    context: context,
    builder: (context) {
      return _BacklogFilterDialog(
        initialLegacyFilters: controller.filters,
        initialBoardFilters: controller.boardFilters,
        projectOptions: _projectOptionsForState(controller.state),
      );
    },
  );
  if (result == null) {
    return;
  }
  await controller.updateFilterState(
    filters: result.legacyFilters,
    boardFilters: result.boardFilters,
  );
}

/// Returns project options from the current ready or empty board state.
List<ProjectOptionReadModel> _projectOptionsForState(
  BacklogBoardScreenState state,
) {
  return switch (state) {
    BacklogBoardReady(:final data) => data.board.projectOptions,
    BacklogBoardEmpty(:final data) => data.board.projectOptions,
    BacklogBoardLoading() ||
    BacklogBoardFailure() => const <ProjectOptionReadModel>[],
  };
}

/// Display label for [sortKey].
String _sortLabel(BacklogSortKey sortKey) {
  return switch (sortKey) {
    BacklogSortKey.custom => 'Custom',
    BacklogSortKey.priority => 'Priority',
    BacklogSortKey.rewardVsEffort => 'Reward',
    BacklogSortKey.age => 'Age',
    BacklogSortKey.project => 'Project',
    BacklogSortKey.timesPushed => 'Pushed',
    BacklogSortKey.duration => 'Duration',
  };
}

/// Display label for [groupMode].
String _groupLabel(BacklogBoardGroupMode groupMode) {
  return switch (groupMode) {
    BacklogBoardGroupMode.none => 'None',
    BacklogBoardGroupMode.project => 'Project',
    BacklogBoardGroupMode.priority => 'Priority',
    BacklogBoardGroupMode.duration => 'Duration',
  };
}

/// Display label for [bucket].
String _bucketLabel(BacklogBoardBucket bucket) {
  return switch (bucket) {
    BacklogBoardBucket.doNext => 'Do Next',
    BacklogBoardBucket.needTimeBlock => 'Need Time Block',
    BacklogBoardBucket.breakUpFirst => 'Break Up First',
    BacklogBoardBucket.notNow => 'Not Now',
  };
}

/// Sort menu options in display order.
const _sortOptions = [
  _MenuOption(value: BacklogSortKey.custom, label: 'Custom'),
  _MenuOption(value: BacklogSortKey.priority, label: 'Priority'),
  _MenuOption(value: BacklogSortKey.rewardVsEffort, label: 'Reward vs Effort'),
  _MenuOption(value: BacklogSortKey.age, label: 'Age'),
  _MenuOption(value: BacklogSortKey.project, label: 'Project'),
  _MenuOption(value: BacklogSortKey.timesPushed, label: 'Times Pushed'),
  _MenuOption(value: BacklogSortKey.duration, label: 'Duration'),
];

/// Group menu options in display order.
const _groupOptions = [
  _MenuOption(value: BacklogBoardGroupMode.none, label: 'None'),
  _MenuOption(value: BacklogBoardGroupMode.project, label: 'Project'),
  _MenuOption(value: BacklogBoardGroupMode.priority, label: 'Priority'),
  _MenuOption(value: BacklogBoardGroupMode.duration, label: 'Duration'),
];
