import '../security/secret_store.dart';

/// User choices for the (Block 2) social layer: the coarse area to publish/
/// browse offers in, and which community relays to talk to. Backed by the OS
/// keystore (via [SecretStore]) to honour "no plaintext at rest" — no
/// shared_preferences.
///
/// Relays default to a small set of well-known public servers so the market
/// works out of the box; the exposure is minimal (offers are opt-in and carry
/// only a coarse geohash) and the user can swap them for a community server.
/// The area stays unset until the user picks one (it's inherently personal).
class SocialSettings {
  SocialSettings(this._store);

  final SecretStore _store;

  static const _areaKey = 'tane.social.area_geohash';
  static const _relaysKey = 'tane.social.relays';
  static const _searchPrecisionKey = 'tane.social.search_precision';

  /// How wide "your zone" searches, as a geohash prefix length: 5 ≈ ±2.4 km
  /// ("very close"), 4 ≈ ±20 km ("around here"), 3 ≈ ±78 km ("my region").
  /// Publishing always emits the full prefix ladder, so a coarser search still
  /// matches finer offers — the default is deliberately wide so a still-sparse
  /// network shows something.
  static const int minSearchPrecision = 3;
  static const int maxSearchPrecision = 5;
  static const int defaultSearchPrecision = 4;

  /// Community servers used automatically so sharing works from the first
  /// launch. The relay pool skips any that are unreachable, so a dead one never
  /// breaks the market; the user never has to know these exist. The Comunes
  /// relay comes first as the reliable, non-commercial home; the public ones
  /// are backup.
  static const List<String> defaultRelays = [
    'wss://relay.comunes.org',
    'wss://nos.lol',
    'wss://relay.damus.io',
    'wss://relay.primal.net',
  ];

  /// The user's coarse area as a low-precision geohash (may be empty). Set
  /// manually or from device location; the transport coarsens it further.
  Future<String> areaGeohash() async => (await _store.read(_areaKey)) ?? '';

  Future<void> setAreaGeohash(String geohash) =>
      _store.write(_areaKey, geohash.trim().toLowerCase());

  /// The relays to talk to. When the user has never configured any, falls back
  /// to [defaultRelays]. Once they save a choice (even an empty one), that wins
  /// — so a privacy-minded user can turn the network off entirely.
  Future<List<String>> relayUrls() async {
    final raw = await _store.read(_relaysKey);
    if (raw == null) return const [...defaultRelays]; // never configured
    return raw.split('\n').where((s) => s.trim().isNotEmpty).toList();
  }

  Future<void> setRelayUrls(List<String> urls) => _store.write(
        _relaysKey,
        urls.map((u) => u.trim()).where((u) => u.isNotEmpty).join('\n'),
      );

  /// How wide to search — a geohash prefix length in [minSearchPrecision,
  /// maxSearchPrecision]. Defaults (and falls back on any garbage) to
  /// [defaultSearchPrecision].
  Future<int> searchPrecision() async {
    final raw = await _store.read(_searchPrecisionKey);
    final value = int.tryParse(raw ?? '');
    if (value == null) return defaultSearchPrecision;
    return _clampPrecision(value);
  }

  Future<void> setSearchPrecision(int precision) =>
      _store.write(_searchPrecisionKey, '${_clampPrecision(precision)}');

  int _clampPrecision(int p) => p < minSearchPrecision
      ? minSearchPrecision
      : (p > maxSearchPrecision ? maxSearchPrecision : p);

  /// Whether the social layer has enough config to attempt going online.
  Future<bool> get isConfigured async =>
      (await relayUrls()).isNotEmpty && (await areaGeohash()).isNotEmpty;
}
