import 'package:afterwork/data/models/user_model.dart';
import 'package:afterwork/domain/entities/user.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  group('UserModel', () {
    const tUserModel = UserModel(
      userId: '123',
      userLastName: 'Doe',
      userFirstName: 'John',
      email: 'john.doe@example.com',
      motDePasse: 'hashedPassword123',
      profileImageUrl: 'https://example.com/profile.jpg',
    );

    final tUserModelJson = {
      'userId': '123',
      'nom': 'Doe',
      'prenoms': 'John',
      'email': 'john.doe@example.com',
      'motDePasse': 'hashedPassword123',
      'profileImageUrl': 'https://example.com/profile.jpg',
    };

    test('should be a subclass of User entity', () {
      // Assert
      expect(tUserModel, isA<User>());
    });

    test('should extend User with all its properties', () {
      // Assert
      expect(tUserModel.userId, '123');
      expect(tUserModel.userLastName, 'Doe');
      expect(tUserModel.userFirstName, 'John');
      expect(tUserModel.email, 'john.doe@example.com');
      expect(tUserModel.motDePasse, 'hashedPassword123');
      expect(tUserModel.profileImageUrl, 'https://example.com/profile.jpg');
    });

    group('fromJson', () {
      test('should return a valid UserModel from JSON', () {
        // Act
        final result = UserModel.fromJson(tUserModelJson);

        // Assert
        expect(result, isA<UserModel>());
        expect(result.userId, '123');
        expect(result.userLastName, 'Doe');
        expect(result.userFirstName, 'John');
        expect(result.email, 'john.doe@example.com');
        expect(result.motDePasse, 'hashedPassword123');
        expect(result.profileImageUrl, 'https://example.com/profile.jpg');
      });

      test('should use default values for missing fields', () {
        // Arrange
        final minimalJson = <String, dynamic>{};

        // Act
        final result = UserModel.fromJson(minimalJson);

        // Assert
        expect(result.userId, '');
        expect(result.userLastName, 'Inconnu');
        expect(result.userFirstName, 'Inconnu');
        expect(result.email, 'inconnu@example.com');
        expect(result.motDePasse, '');
        expect(result.profileImageUrl, '');
      });

      test('should handle partial JSON data', () {
        // Arrange
        final partialJson = {
          'userId': '456',
          'email': 'partial@example.com',
        };

        // Act
        final result = UserModel.fromJson(partialJson);

        // Assert
        expect(result.userId, '456');
        expect(result.email, 'partial@example.com');
        expect(result.userLastName, 'Inconnu'); // Default
        expect(result.userFirstName, 'Inconnu'); // Default
        expect(result.motDePasse, ''); // Default
      });

      test('should handle null values in JSON', () {
        // Arrange
        final jsonWithNulls = {
          'userId': null,
          'nom': null,
          'prenoms': null,
          'email': null,
          'motDePasse': null,
          'profileImageUrl': null,
        };

        // Act
        final result = UserModel.fromJson(jsonWithNulls);

        // Assert
        expect(result.userId, '');
        expect(result.userLastName, 'Inconnu');
        expect(result.userFirstName, 'Inconnu');
        expect(result.email, 'inconnu@example.com');
        expect(result.motDePasse, '');
        expect(result.profileImageUrl, '');
      });
    });

    group('toJson', () {
      test('should return a JSON map containing proper data', () {
        // Act
        final result = tUserModel.toJson();

        // Assert
        expect(result, isA<Map<String, dynamic>>());
        expect(result['id'], '123');
        expect(result['nom'], 'Doe');
        expect(result['prenoms'], 'John');
        expect(result['email'], 'john.doe@example.com');
        expect(result['motDePasse'], 'hashedPassword123');
        expect(result['profileImageUrl'], 'https://example.com/profile.jpg');
      });

      test('should map field names correctly (userId -> id, etc.)', () {
        // Act
        final result = tUserModel.toJson();

        // Assert
        // Vérifie que le mapping des champs est correct
        expect(result.containsKey('id'), isTrue);
        expect(result.containsKey('nom'), isTrue);
        expect(result.containsKey('prenoms'), isTrue);
        // Ne doit PAS contenir les noms de propriétés Dart
        expect(result.containsKey('userId'), isFalse);
        expect(result.containsKey('userLastName'), isFalse);
        expect(result.containsKey('userFirstName'), isFalse);
      });

      test('should be reversible (fromJson -> toJson)', () {
        // Act
        final json = tUserModel.toJson();
        // Adapter le JSON pour fromJson (id -> userId)
        json['userId'] = json['id'];
        final model = UserModel.fromJson(json);

        // Assert
        expect(model.userId, tUserModel.userId);
        expect(model.userLastName, tUserModel.userLastName);
        expect(model.userFirstName, tUserModel.userFirstName);
        expect(model.email, tUserModel.email);
        expect(model.motDePasse, tUserModel.motDePasse);
      });
    });

    group('Equality', () {
      test('should support value equality (from Equatable)', () {
        // Arrange
        const user1 = UserModel(
          userId: '123',
          userLastName: 'Doe',
          userFirstName: 'John',
          email: 'john@example.com',
          motDePasse: 'password',
          profileImageUrl: 'profile.jpg',
        );

        const user2 = UserModel(
          userId: '123',
          userLastName: 'Doe',
          userFirstName: 'John',
          email: 'john@example.com',
          motDePasse: 'password',
          profileImageUrl: 'profile.jpg',
        );

        // Assert
        expect(user1, equals(user2));
        expect(user1.hashCode, equals(user2.hashCode));
      });

      test('should not be equal when fields are different', () {
        // Arrange
        const user1 = UserModel(
          userId: '123',
          userLastName: 'Doe',
          userFirstName: 'John',
          email: 'john@example.com',
          motDePasse: 'password',
          profileImageUrl: 'profile.jpg',
        );

        const user2 = UserModel(
          userId: '456', // Different ID
          userLastName: 'Doe',
          userFirstName: 'John',
          email: 'john@example.com',
          motDePasse: 'password',
          profileImageUrl: 'profile.jpg',
        );

        // Assert
        expect(user1, isNot(equals(user2)));
      });
    });

    group('API Integration', () {
      test('should correctly map API field names', () {
        // Arrange
        final apiResponse = {
          'userId': 'api-123',
          'nom': 'APILastName',
          'prenoms': 'APIFirstName',
          'email': 'api@example.com',
          'motDePasse': 'api-password',
          'profileImageUrl': 'https://api.com/profile.jpg',
        };

        // Act
        final user = UserModel.fromJson(apiResponse);
        final jsonForApi = user.toJson();

        // Assert
        expect(user.userId, 'api-123');
        expect(user.userLastName, 'APILastName');
        expect(user.userFirstName, 'APIFirstName');

        expect(jsonForApi['id'], 'api-123');
        expect(jsonForApi['nom'], 'APILastName');
        expect(jsonForApi['prenoms'], 'APIFirstName');
      });

      test('should handle empty strings from API', () {
        // Arrange
        final apiResponse = {
          'userId': '',
          'nom': '',
          'prenoms': '',
          'email': '',
          'motDePasse': '',
          'profileImageUrl': '',
        };

        // Act
        final user = UserModel.fromJson(apiResponse);

        // Assert
        expect(user.userId, '');
        expect(user.userLastName, ''); // Utilise la valeur vide, pas le défaut
        expect(user.userFirstName, '');
        expect(user.email, '');
      });
    });

    group('Edge Cases', () {
      test('should handle very long strings', () {
        // Arrange
        final longString = 'A' * 1000;
        final jsonWithLongStrings = {
          'userId': longString,
          'nom': longString,
          'prenoms': longString,
          'email': '$longString@example.com',
          'motDePasse': longString,
          'profileImageUrl': 'https://example.com/$longString.jpg',
        };

        // Act
        final user = UserModel.fromJson(jsonWithLongStrings);

        // Assert
        expect(user.userId.length, 1000);
        expect(user.userLastName.length, 1000);
        expect(user.userFirstName.length, 1000);
      });

      test('should handle special characters', () {
        // Arrange
        final jsonWithSpecialChars = {
          'userId': '123',
          'nom': 'Dôe-Smîth',
          'prenoms': 'Jöhn',
          'email': 'john+test@example.com',
          'motDePasse': 'P@ssw0rd!#\$',
          'profileImageUrl': 'https://example.com/profile.jpg',
        };

        // Act
        final user = UserModel.fromJson(jsonWithSpecialChars);

        // Assert
        expect(user.userLastName, 'Dôe-Smîth');
        expect(user.userFirstName, 'Jöhn');
        expect(user.email, 'john+test@example.com');
        expect(user.motDePasse, 'P@ssw0rd!#\$');
      });

      test('should handle unicode characters', () {
        // Arrange
        final jsonWithUnicode = {
          'userId': '123',
          'nom': '山田',
          'prenoms': '太郎',
          'email': 'yamada@example.jp',
          'motDePasse': 'パスワード',
          'profileImageUrl': 'https://example.jp/山田.jpg',
        };

        // Act
        final user = UserModel.fromJson(jsonWithUnicode);

        // Assert
        expect(user.userLastName, '山田');
        expect(user.userFirstName, '太郎');
        expect(user.motDePasse, 'パスワード');
      });
    });
  });
}

