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

part of '../occupancy_policy.dart';

/// Policy classification for one task or external interval.
class OccupancyEntry {
  /// Creates a `OccupancyEntry` 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 OccupancyEntry({
    required this.source,
    required this.category,
    required this.interval,
    required this.task,
    required this.isImmovable,
    required this.blocksAutomaticFlexiblePlacement,
    required this.mayBeExplicitlyOverlappedByRequiredCommitment,
    required this.reportsConflict,
    required this.hiddenByDefault,
  });

  /// Origin of the entry.
  final OccupancySource source;

  /// Scheduling-facing category.
  final OccupancyCategory category;

  /// Interval used by scheduling, or null when the record is unplaced.
  final TimeInterval? interval;

  /// Source task when this entry came from a task record.
  final Task? task;

  /// Stable task id when present.
  String? get taskId => task?.id;

  /// Whether automatic scheduling must leave this entry's placement unchanged.
  final bool isImmovable;

  /// Whether flexible placement must avoid [interval].
  final bool blocksAutomaticFlexiblePlacement;

  /// Whether an explicit critical/inflexible commitment may overlap this entry.
  final bool mayBeExplicitlyOverlappedByRequiredCommitment;

  /// Whether overlaps with this entry should be returned as conflicts.
  final bool reportsConflict;

  /// Whether entry details should be hidden by default in user-facing output.
  final bool hiddenByDefault;

  /// Whether the entry is planned flexible work movable by automatic scheduling.
  bool get isMovablePlannedFlexible {
    return category == OccupancyCategory.movablePlannedFlexible;
  }
}
