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

part of '../today_screen_models.dart';

/// Presentation model for a single compact timeline card.
class TimelineCardModel {
  /// Creates a timeline card model.
  const TimelineCardModel({
    required this.id,
    required this.title,
    required this.typeLabel,
    required this.subtitle,
    required this.timeText,
    required this.startMinutes,
    required this.endMinutes,
    required this.taskType,
    required this.visualKind,
    required this.rewardIconToken,
    required this.difficultyIconToken,
    required this.isCompleted,
    required this.isSelectable,
    required this.showsQuickActions,
    this.showPastTaskPushButton = false,
    this.completionDateContextRequired = false,
    this.completedTimeText,
    this.expectedUpdatedAt,
    this.durationMinutes,
  });

  /// Maps a scheduler timeline item into card presentation data.
  factory TimelineCardModel.fromItem(
    TodayTimelineItem item, {
    required DateTime now,
    Duration timeZoneOffset = Duration.zero,
  }) {
    final start = item.start;
    final end = item.end;
    final visualKind = _visualKindFor(item);
    final isCompleted = item.taskStatus == TaskStatus.completed;
    final showPastTaskPushButton = _showPastTaskPushButton(item, now: now);
    final title = item.item.displayTitle;
    final duration = item.item.durationMinutes;
    final timeText = start == null || end == null
        ? duration == null
              ? ''
              : '$duration min'
        : '${_formatTime(start, timeZoneOffset: timeZoneOffset)} - '
              '${_formatTime(end, timeZoneOffset: timeZoneOffset)}';
    final completionDateContextRequired =
        isCompleted &&
        _completionDateContextRequired(item, timeZoneOffset: timeZoneOffset);
    return TimelineCardModel(
      id: item.id,
      title: title,
      typeLabel: _typeLabelFor(item.taskType, visualKind),
      subtitle: _subtitleFor(
        item,
        visualKind,
        timeText,
        completionDateContextRequired: completionDateContextRequired,
        timeZoneOffset: timeZoneOffset,
      ),
      timeText: timeText,
      startMinutes: _minutesSinceMidnight(
        start,
        timeZoneOffset: timeZoneOffset,
      ),
      endMinutes: _minutesSinceMidnight(end, timeZoneOffset: timeZoneOffset),
      taskType: item.taskType,
      visualKind: visualKind,
      rewardIconToken: item.item.rewardIconToken,
      difficultyIconToken: item.item.difficultyIconToken,
      durationMinutes: duration,
      completionDateContextRequired: completionDateContextRequired,
      completedTimeText: isCompleted
          ? _completionDisplayText(
              item,
              includeDate: completionDateContextRequired,
              timeZoneOffset: timeZoneOffset,
            )
          : null,
      expectedUpdatedAt: item.item.updatedAt,
      isCompleted: isCompleted,
      isSelectable: true,
      showPastTaskPushButton: showPastTaskPushButton,
      showsQuickActions:
          !showPastTaskPushButton &&
          !isCompleted &&
          visualKind != TaskVisualKind.freeSlot,
    );
  }

  /// Stable card identifier.
  final String id;

  /// Primary task title shown on the card.
  final String title;

  /// Short task type label.
  final String typeLabel;

  /// Secondary line shown under the title.
  final String subtitle;

  /// Display-ready time or duration text.
  final String timeText;

  /// Display-ready completion time or date-time, if the task has been completed.
  final String? completedTimeText;

  /// Expected update timestamp for stale-write protection.
  final DateTime? expectedUpdatedAt;

  /// Whether completion text includes date context because completion crossed dates.
  final bool completionDateContextRequired;

  /// Card start position in minutes since midnight.
  final int startMinutes;

  /// Card end position in minutes since midnight.
  final int endMinutes;

  /// Optional task duration in minutes.
  final int? durationMinutes;

  /// Source task scheduling behavior type.
  final TaskType taskType;

  /// Visual category used for styling.
  final TaskVisualKind visualKind;

  /// Reward icon token from the scheduler core.
  final TimelineRewardIconToken rewardIconToken;

  /// Difficulty icon token from the scheduler core.
  final TimelineDifficultyIconToken difficultyIconToken;

  /// Whether the card represents completed work.
  final bool isCompleted;

  /// Whether tapping the card should open its selection modal.
  final bool isSelectable;

  /// Whether the card should show compact quick-action controls.
  final bool showsQuickActions;

  /// Whether the card should show the full overdue-task push control.
  final bool showPastTaskPushButton;

  /// Accessible label for the full overdue-task push control.
  String get pastTaskPushSemanticLabel => 'Push overdue task';

  /// Whether the left status control can toggle this task's completion.
  bool get canToggleCompletion {
    return switch (taskType) {
      TaskType.flexible || TaskType.critical || TaskType.inflexible => true,
      TaskType.locked || TaskType.surprise || TaskType.freeSlot => false,
    };
  }

  /// Whether the left status control can complete this task.
  bool get canComplete => canToggleCompletion && !isCompleted;

  /// Whether the left status control can return this task to planned.
  bool get canUncomplete => canToggleCompletion && isCompleted;

  /// Accessibility and modal label for the reward icon.
  String get rewardLabel {
    return switch (rewardIconToken) {
      TimelineRewardIconToken.notSet => 'Reward not set',
      TimelineRewardIconToken.veryLow => 'Reward level 1',
      TimelineRewardIconToken.low => 'Reward level 2',
      TimelineRewardIconToken.medium => 'Reward level 3',
      TimelineRewardIconToken.high => 'Reward level 4',
      TimelineRewardIconToken.veryHigh => 'Reward level 5',
    };
  }

  /// Accessibility and modal label for the effort icon.
  String get effortLabel {
    return switch (difficultyIconToken) {
      TimelineDifficultyIconToken.notSet => 'Effort not set',
      TimelineDifficultyIconToken.veryEasy => 'Very easy effort',
      TimelineDifficultyIconToken.easy => 'Easy effort',
      TimelineDifficultyIconToken.medium => 'Medium effort',
      TimelineDifficultyIconToken.hard => 'Hard effort',
      TimelineDifficultyIconToken.veryHard => 'Very hard effort',
    };
  }
}
