import 'package:flutter_test/flutter_test.dart';
import 'package:fotodocumentation/controller/login_controller.dart';
import 'package:fotodocumentation/utils/di_container.dart';
import 'package:fotodocumentation/utils/http_client_utils.dart';
import 'package:fotodocumentation/utils/jwt_token_storage.dart';
import 'package:http/http.dart' as http;
import 'package:mockito/mockito.dart';

import '../testing/test_http_client_utils.dart';
import '../testing/test_utils.mocks.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();
  DiContainer.instance.initState();
  var jwtTokenStorage = MockJwtTokenStorage();
  when(jwtTokenStorage.getAccessToken()).thenAnswer((_) async => null);
  DiContainer.instance.put(JwtTokenStorage, jwtTokenStorage);

  LoginController controller = LoginControllerImpl();

  group('LoginController', () {
    test('authenticate returns JwtTokenPairDto on successful login', () async {
      final client = MockClient();
      DiContainer.instance.put(HttpClientUtils, TestHttpCLientUtilsImpl(client));

      when(jwtTokenStorage.saveTokens(any, any)).thenAnswer((_) async => {});
      when(client.get(Uri.parse('http://localhost:8080/api/login'), headers: anyNamed('headers')))
          .thenAnswer((_) async => http.Response(_jwtTokenPairJson, 200));

      var reply = await controller.authenticate("testuser", "testpass");
      expect(reply.jwtTokenPairDto, isNotNull);
      expect(reply.jwtTokenPairDto?.accessToken, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access");
      expect(reply.jwtTokenPairDto?.refreshToken, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh");
      verify(jwtTokenStorage.saveTokens(any, any)).called(1);
    });



    test('authenticate returns null on authentication failure (401)', () async {
      final client = MockClient();
      DiContainer.instance.put(HttpClientUtils, TestHttpCLientUtilsImpl(client));

      when(client.get(Uri.parse('http://localhost:8080/api/login'), headers: anyNamed('headers')))
          .thenAnswer((_) async => http.Response('Unauthorized', 401));

      var reply = await controller.authenticate("wronguser", "wrongpass");
      expect(reply.jwtTokenPairDto, isNull);
      verifyNever(jwtTokenStorage.saveTokens(any, any));
    });

    test('authenticate returns null on server error (500)', () async {
      final client = MockClient();
      DiContainer.instance.put(HttpClientUtils, TestHttpCLientUtilsImpl(client));

      when(client.get(Uri.parse('http://localhost:8080/api/login'), headers: anyNamed('headers')))
          .thenAnswer((_) async => http.Response('Internal Server Error', 500));

      var reply = await controller.authenticate("testuser", "testpass");
      expect(reply.jwtTokenPairDto, isNull);
      verifyNever(jwtTokenStorage.saveTokens(any, any));
    });

    test('authenticate returns null on exception', () async {
      final client = MockClient();
      DiContainer.instance.put(HttpClientUtils, TestHttpCLientUtilsImpl(client));

      when(client.get(Uri.parse('http://localhost:8080/api/login'), headers: anyNamed('headers')))
          .thenThrow(Exception('Network error'));

      var reply = await controller.authenticate("testuser", "testpass");
      expect(reply.jwtTokenPairDto, isNull);
      verifyNever(jwtTokenStorage.saveTokens(any, any));
    });
  });
}

String _jwtTokenPairJson = '''{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh"
}''';
