/// Nextcloud share permission bitmask helpers. These mirror the constants the
/// OCS `files_sharing` API expects in the `permissions` field. Kept as pure
/// functions (no Flutter/IO) so they are unit-testable.
library;

/// Individual permission bits (Nextcloud `OCS\Constants`).
const int kPermissionRead = 1;
const int kPermissionUpdate = 2;
const int kPermissionCreate = 4;
const int kPermissionDelete = 8;
const int kPermissionShare = 16;

/// User-facing presets that map onto a bitmask.
enum SharePreset {
  /// Recipient can only view/download.
  readOnly,

  /// Recipient can view, edit, add and remove (full editing).
  edit,

  /// Upload-only "file request" — recipient can add files to a folder but not
  /// see existing contents. Only meaningful for folders.
  fileDrop,
}

extension SharePresetLabel on SharePreset {
  String get label {
    switch (this) {
      case SharePreset.readOnly:
        return 'Nur Lesen';
      case SharePreset.edit:
        return 'Bearbeiten';
      case SharePreset.fileDrop:
        return 'Datei-Anfrage';
    }
  }
}

/// Returns true if [mask] contains the given [flag].
bool hasPermission(int mask, int flag) => mask & flag == flag;

/// Builds the permission bitmask for a [preset].
///
/// [isFolder] matters for the `edit` preset: a file can only carry
/// read+update, while a folder additionally supports create+delete. Nextcloud
/// rejects create/delete on a file ("Failed to update share"), so they must be
/// omitted there. When [allowReshare] is true the reshare bit is added to the
/// editing presets — mirroring how the Nextcloud clients respect the
/// `resharing` capability.
int permissionsFor(
  SharePreset preset, {
  bool allowReshare = false,
  bool isFolder = false,
}) {
  switch (preset) {
    case SharePreset.readOnly:
      return kPermissionRead;
    case SharePreset.edit:
      var base = kPermissionRead | kPermissionUpdate;
      if (isFolder) base |= kPermissionCreate | kPermissionDelete;
      return allowReshare ? base | kPermissionShare : base;
    case SharePreset.fileDrop:
      return kPermissionCreate;
  }
}

/// Classifies an arbitrary permission bitmask into the closest preset, or null
/// if it doesn't match any (e.g. a custom combination). The reshare bit is
/// ignored for matching so an "edit" share stays "edit" regardless of reshare.
SharePreset? presetFromBitmask(int mask) {
  final normalized = mask & ~kPermissionShare;
  if (normalized == kPermissionCreate) return SharePreset.fileDrop;
  if (normalized == kPermissionRead) return SharePreset.readOnly;
  // Any read share that also carries a write bit (update/create/delete) is
  // surfaced as "edit".
  const writeBits = kPermissionUpdate | kPermissionCreate | kPermissionDelete;
  if (hasPermission(normalized, kPermissionRead) &&
      normalized & writeBits != 0) {
    return SharePreset.edit;
  }
  return null;
}
