import 'dart:io';
import 'package:path/path.dart' as p;

/// Operator-managed registry auth token, kept at
/// `~/.chain/registry-token` (mode 0600 on Unix). The hub reads
/// this file at install time when `CHAIN_REGISTRY_TOKEN` is unset
/// — see `download_to_temp` in `crates/fai_hub/src/lib.rs`.
///
/// Studio writes the file directly so a fresh install never
/// requires the operator to fiddle with shell env vars.
class RegistryToken {
  static String _faiHome() {
    final home =
        Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
    if (home == null || home.isEmpty) {
      throw StateError('Cannot resolve home directory (no HOME / USERPROFILE)');
    }
    return p.join(home, '.fai');
  }

  /// Absolute path to the token file.
  static String get path => p.join(_faiHome(), 'registry-token');

  /// True iff the file exists with a non-empty trimmed body.
  static Future<bool> isConfigured() async {
    final f = File(path);
    if (!await f.exists()) return false;
    final content = await f.readAsString();
    return content.trim().isNotEmpty;
  }

  /// Length of the trimmed token, or null when the file is
  /// missing / empty. Used for status display ("Configured
  /// (40 chars)") without ever surfacing the secret.
  static Future<int?> charCount() async {
    final f = File(path);
    if (!await f.exists()) return null;
    final content = await f.readAsString();
    final trimmed = content.trim();
    return trimmed.isEmpty ? null : trimmed.length;
  }

  /// Persist [token] to disk, creating `~/.chain/` if needed.
  /// On Unix the file is chmod-ed to 0600 (owner read/write
  /// only). On Windows the default user-ACL is left alone —
  /// best-effort, no PowerShell handshake.
  static Future<void> write(String token) async {
    final f = File(path);
    await f.parent.create(recursive: true);
    await f.writeAsString(token.trim(), flush: true);
    if (Platform.isLinux || Platform.isMacOS) {
      try {
        await Process.run('chmod', ['600', f.path]);
      } catch (_) {
        // best-effort; if chmod is unavailable the file still
        // exists with default perms (usually 0644, world-readable
        // but only on the operator's own machine).
      }
    }
  }

  /// Delete the token file. No-op when the file doesn't exist.
  static Future<void> delete() async {
    final f = File(path);
    if (await f.exists()) await f.delete();
  }
}
