/// Subset of Nextcloud's `files_sharing` capabilities block that the mobile
/// sharing UI gates on. Nextcloud reports these per authenticated user, so a
/// group that an admin excluded from creating public links sees
/// `public.enabled == false` here — exactly how the web UI hides those buttons.
///
/// The block is deeply nested and varies between server versions, so this is
/// parsed by hand from the raw OCS map with safe fallbacks rather than via
/// code generation. Missing fields default to the most restrictive value so a
/// newer/older server never accidentally unlocks a capability.
class NextcloudSharingCapabilities {
  /// `files_sharing.api_enabled` — master switch. When false the user may not
  /// create any share (user, group or link).
  final bool apiEnabled;

  /// `files_sharing.public.enabled` — public link shares allowed.
  final bool publicEnabled;

  /// `files_sharing.public.multiple_links` — more than one link per file.
  final bool publicMultipleLinks;

  /// `files_sharing.public.upload` — public upload / file-drop folders.
  final bool publicUploadEnabled;

  /// `files_sharing.public.password.enforced` — a password is mandatory on
  /// public links, so the create flow must collect one upfront.
  final bool publicPasswordEnforced;

  /// `files_sharing.public.expire_date.enabled`.
  final bool publicExpireEnabled;

  /// `files_sharing.public.expire_date.days` — default/maximum lifetime.
  final int? publicExpireDays;

  /// `files_sharing.public.expire_date.enforced` — expiry cannot be removed.
  final bool publicExpireEnforced;

  /// `files_sharing.group.enabled` (falls back to the older `group_sharing`).
  final bool groupEnabled;

  /// `files_sharing.resharing` — recipients may reshare.
  final bool resharing;

  // --- password_policy (a sibling capability of files_sharing) ---
  // These let the link-password UI state the rules up front instead of only
  // surfacing them after the server rejects a weak password. The
  // "non-common password" (breach) check can only be enforced server-side.

  /// `password_policy.minLength`.
  final int? passwordMinLength;

  /// `password_policy.enforceUpperLowerCase`.
  final bool passwordEnforceUpperLower;

  /// `password_policy.enforceNumericCharacters`.
  final bool passwordEnforceNumeric;

  /// `password_policy.enforceSpecialCharacters`.
  final bool passwordEnforceSpecial;

  const NextcloudSharingCapabilities({
    this.apiEnabled = false,
    this.publicEnabled = false,
    this.publicMultipleLinks = false,
    this.publicUploadEnabled = false,
    this.publicPasswordEnforced = false,
    this.publicExpireEnabled = false,
    this.publicExpireDays,
    this.publicExpireEnforced = false,
    this.groupEnabled = false,
    this.resharing = false,
    this.passwordMinLength,
    this.passwordEnforceUpperLower = false,
    this.passwordEnforceNumeric = false,
    this.passwordEnforceSpecial = false,
  });

  /// Parses the `files_sharing` sub-map of an OCS `cloud/capabilities`
  /// response, plus the optional sibling `password_policy` map. Tolerates
  /// missing intermediate maps and type drift.
  factory NextcloudSharingCapabilities.fromFilesSharing(
    Map<String, dynamic> filesSharing, {
    Map<String, dynamic>? passwordPolicy,
  }) {
    Map<String, dynamic>? sub(Map<String, dynamic>? m, String key) {
      final value = m?[key];
      return value is Map<String, dynamic> ? value : null;
    }

    bool boolAt(Map<String, dynamic>? m, String key) => m?[key] == true;
    int? intAt(Map<String, dynamic>? m, String key) {
      final v = m?[key];
      if (v is int) return v;
      if (v is String) return int.tryParse(v);
      return null;
    }

    final public = sub(filesSharing, 'public');
    final password = sub(public, 'password');
    final expire = sub(public, 'expire_date');
    final group = sub(filesSharing, 'group');

    return NextcloudSharingCapabilities(
      apiEnabled: boolAt(filesSharing, 'api_enabled'),
      publicEnabled: boolAt(public, 'enabled'),
      publicMultipleLinks: boolAt(public, 'multiple_links'),
      publicUploadEnabled: boolAt(public, 'upload'),
      publicPasswordEnforced: boolAt(password, 'enforced'),
      publicExpireEnabled: boolAt(expire, 'enabled'),
      publicExpireDays: intAt(expire, 'days'),
      publicExpireEnforced: boolAt(expire, 'enforced'),
      // Newer servers nest it under `group.enabled`; older ones expose a flat
      // `group_sharing` boolean.
      groupEnabled:
          boolAt(group, 'enabled') || boolAt(filesSharing, 'group_sharing'),
      resharing: boolAt(filesSharing, 'resharing'),
      passwordMinLength: intAt(passwordPolicy, 'minLength'),
      passwordEnforceUpperLower: boolAt(
        passwordPolicy,
        'enforceUpperLowerCase',
      ),
      passwordEnforceNumeric: boolAt(
        passwordPolicy,
        'enforceNumericCharacters',
      ),
      passwordEnforceSpecial: boolAt(
        passwordPolicy,
        'enforceSpecialCharacters',
      ),
    );
  }
}
