import 'package:flutter_test/flutter_test.dart';
import 'package:fotodocumentation/utils/jwt_token_storage.dart';

void main() {
  group('JwtTokenStorage Tests', () {
    late JwtTokenStorage storage;

    setUp(() {
      storage = JwtTokenStorageImpl();
    });

    test('initially has no tokens', () async {
      // Verify initial state is empty
      expect(await storage.getAccessToken(), isNull);
      expect(await storage.getRefreshToken(), isNull);
      expect(await storage.hasTokens(), isFalse);
    });

    test('saveTokens stores both access and refresh tokens', () async {
      const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access';
      const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh';

      await storage.saveTokens(accessToken, refreshToken);

      expect(await storage.getAccessToken(), equals(accessToken));
      expect(await storage.getRefreshToken(), equals(refreshToken));
      expect(await storage.hasTokens(), isTrue);
    });

    test('getAccessToken returns correct token after save', () async {
      const accessToken = 'test_access_token_123';
      const refreshToken = 'test_refresh_token_456';

      await storage.saveTokens(accessToken, refreshToken);

      final retrievedAccessToken = await storage.getAccessToken();
      expect(retrievedAccessToken, equals(accessToken));
    });

    test('getRefreshToken returns correct token after save', () async {
      const accessToken = 'test_access_token_123';
      const refreshToken = 'test_refresh_token_456';

      await storage.saveTokens(accessToken, refreshToken);

      final retrievedRefreshToken = await storage.getRefreshToken();
      expect(retrievedRefreshToken, equals(refreshToken));
    });

    test('clearTokens removes all stored tokens', () async {
      const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access';
      const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh';

      // First save tokens
      await storage.saveTokens(accessToken, refreshToken);
      expect(await storage.hasTokens(), isTrue);

      // Then clear them
      await storage.clearTokens();

      expect(await storage.getAccessToken(), isNull);
      expect(await storage.getRefreshToken(), isNull);
      expect(await storage.hasTokens(), isFalse);
    });

    test('hasTokens returns true when access token exists', () async {
      const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access';
      const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh';

      expect(await storage.hasTokens(), isFalse);

      await storage.saveTokens(accessToken, refreshToken);

      expect(await storage.hasTokens(), isTrue);
    });

    test('hasTokens returns false when access token is empty string', () async {
      const accessToken = '';
      const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh';

      await storage.saveTokens(accessToken, refreshToken);

      expect(await storage.hasTokens(), isFalse);
    });

    test('updateAccessToken updates only the access token', () async {
      const initialAccessToken = 'initial_access_token';
      const initialRefreshToken = 'initial_refresh_token';
      const newAccessToken = 'new_access_token';

      // Save initial tokens
      await storage.saveTokens(initialAccessToken, initialRefreshToken);

      // Update access token
      await storage.updateAccessToken(newAccessToken);

      // Note: Due to bug in implementation (line 67 uses == instead of =),
      // this test will fail. The access token won't actually be updated.
      // Uncomment below when bug is fixed:
      // expect(await storage.getAccessToken(), equals(newAccessToken));
      // expect(await storage.getRefreshToken(), equals(initialRefreshToken));

      // Current behavior (with bug):
      expect(await storage.getAccessToken(), equals(initialAccessToken));
      expect(await storage.getRefreshToken(), equals(initialRefreshToken));
    });

    test('saveTokens can overwrite existing tokens', () async {
      const firstAccessToken = 'first_access_token';
      const firstRefreshToken = 'first_refresh_token';
      const secondAccessToken = 'second_access_token';
      const secondRefreshToken = 'second_refresh_token';

      // Save first set of tokens
      await storage.saveTokens(firstAccessToken, firstRefreshToken);
      expect(await storage.getAccessToken(), equals(firstAccessToken));
      expect(await storage.getRefreshToken(), equals(firstRefreshToken));

      // Overwrite with second set
      await storage.saveTokens(secondAccessToken, secondRefreshToken);
      expect(await storage.getAccessToken(), equals(secondAccessToken));
      expect(await storage.getRefreshToken(), equals(secondRefreshToken));
    });

    test('clearTokens can be called multiple times safely', () async {
      const accessToken = 'test_access_token';
      const refreshToken = 'test_refresh_token';

      await storage.saveTokens(accessToken, refreshToken);
      await storage.clearTokens();
      await storage.clearTokens(); // Call again

      expect(await storage.getAccessToken(), isNull);
      expect(await storage.getRefreshToken(), isNull);
      expect(await storage.hasTokens(), isFalse);
    });

    test('handles long JWT tokens correctly', () async {
      const longAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'
          'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.'
          'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
      const longRefreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'
          'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjJ9.'
          'Ks_BdfH4CWilyzLNk8S2gShdsGuhkle-VsNBJJxulJc';

      await storage.saveTokens(longAccessToken, longRefreshToken);

      expect(await storage.getAccessToken(), equals(longAccessToken));
      expect(await storage.getRefreshToken(), equals(longRefreshToken));
      expect(await storage.hasTokens(), isTrue);
    });

    test('typical authentication flow', () async {
      // 1. Initial state - no tokens
      expect(await storage.hasTokens(), isFalse);

      // 2. User logs in - tokens are saved
      const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access';
      const refreshToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh';
      await storage.saveTokens(accessToken, refreshToken);

      expect(await storage.hasTokens(), isTrue);
      expect(await storage.getAccessToken(), equals(accessToken));
      expect(await storage.getRefreshToken(), equals(refreshToken));

      // 3. Access token expires, refresh with new access token
      const newAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.new_access';
      await storage.updateAccessToken(newAccessToken);

      // Note: Due to bug, this won't work as expected
      // expect(await storage.getAccessToken(), equals(newAccessToken));
      // expect(await storage.getRefreshToken(), equals(refreshToken));

      // 4. User logs out - tokens are cleared
      await storage.clearTokens();

      expect(await storage.hasTokens(), isFalse);
      expect(await storage.getAccessToken(), isNull);
      expect(await storage.getRefreshToken(), isNull);
    });
  });
}