import 'package:flutter_test/flutter_test.dart';
import 'package:matrix/matrix.dart';
import 'package:pyramid/core/soft_logout_guard.dart';

/// Fake-Client: nur `refreshAccessToken` ist implementiert. Jeder andere
/// SDK-Aufruf (insbesondere `logout()`/`clear()`!) schlägt laut mit
/// NoSuchMethodError fehl – so würde der Test es sofort merken, wenn der
/// Guard je etwas anderes am Client aufriefe als den Refresh.
class _FakeClient implements Client {
  _FakeClient(this._onRefresh);

  final Future<void> Function(int attempt) _onRefresh;
  int attempts = 0;

  @override
  Future<void> refreshAccessToken({Duration? customRefreshTokenLifetime}) {
    attempts++;
    return _onRefresh(attempts);
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

void main() {
  test('erfolgreicher Refresh beim ersten Versuch: genau 1 Aufruf', () async {
    final client = _FakeClient((_) async {});
    await guardedSoftLogoutRefresh(client);
    expect(client.attempts, 1);
  });

  test(
    'transienter Fehler (z. B. Netz weg / Token-Rotations-Race mit dem '
    'Push-Isolate): Retry heilt, kein Fehler nach außen',
    () async {
      final client = _FakeClient((attempt) async {
        if (attempt == 1) throw Exception('Netzwerkfehler');
      });
      await guardedSoftLogoutRefresh(client);
      expect(client.attempts, 2);
    },
  );

  test(
    'dauerhafter Fehler: genau 3 Versuche, und der Guard wirft NIE '
    '(CLAUDE.md: Fehlerpfade dürfen nie in einem stillen Logout enden – '
    'ein Throw hier würde im SDK zu logout()+clear() eskalieren)',
    () async {
      final client = _FakeClient((_) async {
        throw Exception('Server dauerhaft nicht erreichbar');
      });
      // Darf trotz 3 Fehlversuchen normal (ohne Exception) zurückkehren.
      await guardedSoftLogoutRefresh(client);
      expect(client.attempts, 3);
    },
    // Der Guard wartet real 2s+4s zwischen den Versuchen.
    timeout: const Timeout(Duration(seconds: 30)),
  );

  test('auch ein Error (nicht nur Exception) im Refresh entkommt nie', () async {
    final client = _FakeClient((_) async {
      throw StateError('unerwarteter Zustand');
    });
    await guardedSoftLogoutRefresh(client);
    expect(client.attempts, 3);
  }, timeout: const Timeout(Duration(seconds: 30)));
}
