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

part of '../task_timeline_card.dart';

/// Private implementation type for `_TrailingControls` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _TrailingControls extends StatelessWidget {
  /// Creates a `_TrailingControls` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  const _TrailingControls({
    required this.card,
    required this.colors,
    required this.metrics,
    required this.actionsVisible,
    required this.pushRunning,
    this.onPushToNext,
    this.onPushToTomorrow,
    this.onPushToBacklog,
  });

  /// Stores the `card` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final TimelineCardModel card;

  /// Stores the `colors` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final _CardColors colors;

  /// Stores the `metrics` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final _CardMetrics metrics;

  /// Stores the `actionsVisible` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final bool actionsVisible;

  /// Stores the `pushRunning` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final bool pushRunning;

  /// Callback invoked when Push to next is selected.
  final Future<void> Function()? onPushToNext;

  /// Callback invoked when Push to tomorrow is selected.
  final Future<void> Function()? onPushToTomorrow;

  /// Callback invoked when Push to backlog is selected.
  final Future<void> Function()? onPushToBacklog;

  /// 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: [
        if (card.showsQuickActions)
          _QuickActions(
            card: card,
            color: colors.accent,
            backgroundColor: colors.background.withValues(alpha: 1),
            metrics: metrics,
            visible: actionsVisible,
            pushRunning: pushRunning,
            onPushToNext: onPushToNext,
            onPushToTomorrow: onPushToTomorrow,
            onPushToBacklog: onPushToBacklog,
          ),
        if (card.showPastTaskPushButton) ...[
          _PastTaskPushButton(
            card: card,
            color: colors.accent,
            backgroundColor: colors.background,
            metrics: metrics,
            isRunning: pushRunning,
            onPushToNext: onPushToNext,
            onPushToTomorrow: onPushToTomorrow,
            onPushToBacklog: onPushToBacklog,
          ),
          SizedBox(width: metrics.pushButtonGap),
        ],
        RewardIcon(color: colors.reward, size: metrics.rewardIconSize),
        SizedBox(width: metrics.indicatorGap),
        DifficultyBars(
          difficulty: card.difficultyIconToken,
          color: colors.reward,
          size: metrics.difficultySize,
        ),
      ],
    );
  }
}

/// Menu destinations exposed by the overdue-task Push button.
enum _PastTaskPushDestination {
  /// Pushes the task to the next available slot.
  next,

  /// Pushes the task to tomorrow's first available slot.
  tomorrow,

  /// Pushes the task to Backlog.
  backlog,
}

/// Menu item model for push destination options.
class _PushDestinationOption {
  /// Creates one push destination menu option.
  const _PushDestinationOption({
    required this.destination,
    required this.label,
    required this.callback,
  });

  /// Destination selected by this option.
  final _PastTaskPushDestination destination;

  /// Visible label for this option.
  final String label;

  /// Callback invoked when this option is selected.
  final Future<void> Function()? callback;
}

/// Runs [callback] for [destination] when that destination has a callback.
void _selectPushDestination(
  _PastTaskPushDestination destination,
  List<_PushDestinationOption> options,
) {
  for (final option in options) {
    if (option.destination != destination) {
      continue;
    }
    final callback = option.callback;
    if (callback != null) {
      unawaited(callback());
    }
    return;
  }
}

/// Builds push destination menu options.
List<_PushDestinationOption> _pushDestinationOptions({
  required Future<void> Function()? onPushToNext,
  required Future<void> Function()? onPushToTomorrow,
  required Future<void> Function()? onPushToBacklog,
}) {
  return [
    _PushDestinationOption(
      destination: _PastTaskPushDestination.next,
      label: 'Push to next',
      callback: onPushToNext,
    ),
    _PushDestinationOption(
      destination: _PastTaskPushDestination.tomorrow,
      label: 'Push to tomorrow',
      callback: onPushToTomorrow,
    ),
    _PushDestinationOption(
      destination: _PastTaskPushDestination.backlog,
      label: 'Push to backlog',
      callback: onPushToBacklog,
    ),
  ];
}

/// Whether any push destination option has an active callback.
bool _hasEnabledPushDestination(List<_PushDestinationOption> options) {
  return options.any((option) => option.callback != null);
}

/// Builds popup menu entries for push destination options.
List<PopupMenuEntry<_PastTaskPushDestination>> _pushDestinationMenuItems(
  List<_PushDestinationOption> options,
) {
  return [
    for (final option in options)
      PopupMenuItem<_PastTaskPushDestination>(
        value: option.destination,
        enabled: option.callback != null,
        child: Text(option.label),
      ),
  ];
}

/// Private implementation type for `_PastTaskPushButton` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _PastTaskPushButton extends StatelessWidget {
  /// Creates a `_PastTaskPushButton` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  const _PastTaskPushButton({
    required this.card,
    required this.color,
    required this.backgroundColor,
    required this.metrics,
    required this.isRunning,
    this.onPushToNext,
    this.onPushToTomorrow,
    this.onPushToBacklog,
  });

  /// Stores the `card` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final TimelineCardModel card;

  /// Stores the `color` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final Color color;

  /// Stores the `backgroundColor` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final Color backgroundColor;

  /// Stores the `metrics` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final _CardMetrics metrics;

  /// Stores the `isRunning` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final bool isRunning;

  /// Callback invoked when Push to next is selected.
  final Future<void> Function()? onPushToNext;

  /// Callback invoked when Push to tomorrow is selected.
  final Future<void> Function()? onPushToTomorrow;

  /// Callback invoked when Push to backlog is selected.
  final Future<void> Function()? onPushToBacklog;

  /// 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 options = _pushDestinationOptions(
      onPushToNext: onPushToNext,
      onPushToTomorrow: onPushToTomorrow,
      onPushToBacklog: onPushToBacklog,
    );
    final enabled = !isRunning && _hasEnabledPushDestination(options);
    return PopupMenuButton<_PastTaskPushDestination>(
      key: ValueKey('${card.id}-push-button'),
      tooltip: card.pastTaskPushSemanticLabel,
      enabled: enabled,
      color: const Color(0xFF122018),
      elevation: 8,
      position: PopupMenuPosition.under,
      onSelected: (destination) => _selectPushDestination(destination, options),
      itemBuilder: (context) => _pushDestinationMenuItems(options),
      child: Semantics(
        button: true,
        enabled: enabled,
        label: card.pastTaskPushSemanticLabel,
        child: Container(
          width: metrics.pushButtonWidth,
          height: metrics.pushButtonHeight,
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: backgroundColor.withValues(alpha: 0.96),
            border: Border.all(color: color, width: 1),
            borderRadius: BorderRadius.circular(6),
          ),
          child: Text(
            'Push',
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(
              color: color,
              fontSize: (11 * metrics.scale).clamp(8.0, 11.0).toDouble(),
              fontWeight: FontWeight.w800,
              height: 1,
            ),
          ),
        ),
      ),
    );
  }
}
