import 'package:flutter/foundation.dart';

import '../../share_intent/remote_file_ref.dart';

/// Snapshot of a single download's lifecycle. UI widgets rebuild whenever the
/// owning [DownloadJob.status] notifier emits a new instance.
sealed class DownloadStatus {
  const DownloadStatus();
}

class DownloadInProgress extends DownloadStatus {
  const DownloadInProgress(this.percent);

  /// 0–100, or a value `<= 0` while the total size is still unknown
  /// (indeterminate progress).
  final double percent;
}

class DownloadDone extends DownloadStatus {
  const DownloadDone(this.localPath);
  final String localPath;
}

class DownloadCancelled extends DownloadStatus {
  const DownloadCancelled();
}

class DownloadFailed extends DownloadStatus {
  const DownloadFailed(this.message);
  final String message;
}

/// Tracks a single in-flight or finished download. Survives widget dispose so
/// that re-entering a screen (or opening the downloads overview) reattaches to
/// the same job. Kept engine-agnostic on purpose — the native
/// `background_downloader` task lives entirely inside [DownloadManager].
class DownloadJob {
  DownloadJob({
    required this.remotePath,
    required this.name,
    this.remoteFile,
  });

  final String remotePath;
  final String name;

  /// Server-side reference so the viewer can offer "An Chat senden" /
  /// "In Cloud speichern" for downloads triggered from Files or Talk.
  final RemoteFileRef? remoteFile;

  /// Native task id, set by [DownloadManager] once the task is enqueued.
  String? taskId;

  /// True once the finished file has been opened (auto-open or from the
  /// overview). Opened jobs drop out of the downloads tray.
  bool opened = false;

  final ValueNotifier<DownloadStatus> status = ValueNotifier(
    const DownloadInProgress(0),
  );

  bool get isFinished =>
      status.value is DownloadDone ||
      status.value is DownloadFailed ||
      status.value is DownloadCancelled;

  bool get isDone => status.value is DownloadDone;
  bool get isFailed => status.value is DownloadFailed;
  bool get isCancelled => status.value is DownloadCancelled;

  /// Local file path once finished, else null.
  String? get localPath {
    final value = status.value;
    return value is DownloadDone ? value.localPath : null;
  }

  void dispose() => status.dispose();
}
