// ABOUTME: Comprehensive tests for enhanced validation features in Step 8
// ABOUTME: Tests validation exception handling, data integrity checks, and improved error feedback

import 'package:flutter_test/flutter_test.dart';
import 'package:health_tracker/services/validation_service.dart';
import 'package:health_tracker/utils/validation_exception.dart';
import 'package:health_tracker/services/data_integrity_service.dart';
import 'package:health_tracker/widgets/validation/validated_number_field.dart';
import 'package:health_tracker/widgets/validation/validated_date_picker.dart';
import 'package:health_tracker/widgets/validation/error_display_widget.dart';
import 'package:health_tracker/models/weight_entry.dart';
import 'package:health_tracker/models/blood_pressure_entry.dart';
import 'package:health_tracker/models/mood_entry.dart';
import 'package:health_tracker/models/mood_type.dart';
import 'package:health_tracker/utils/error_handler.dart';

void main() {
  group('Enhanced Validation Features', () {
    late ValidationService validationService;
    late DataIntegrityService dataIntegrityService;
    late ErrorHandler errorHandler;

    setUp(() {
      validationService = ValidationService.instance;
      dataIntegrityService = DataIntegrityService.instance;
      errorHandler = ErrorHandler.instance;
    });

    group('ValidationException', () {
      test('should create validation exception from validation result', () {
        final validationResult = ValidationResult(
          isValid: false,
          errors: ['Field is required', 'Value is too low'],
          warnings: ['Consider using metric units'],
        );

        final exception = ValidationException.fromValidationResult(
          'weight',
          validationResult,
        );

        expect(exception.message, equals('Field is required'));
        expect(exception.field, equals('weight'));
        expect(exception.errors, equals(['Field is required', 'Value is too low']));
        expect(exception.warnings, equals(['Consider using metric units']));
        expect(exception.type, equals(ValidationErrorType.fieldValidation));
      });

      test('should create duplicate validation exception', () {
        final exception = ValidationException.duplicate(
          message: 'Entry already exists',
          field: 'weight',
          details: 'Similar weight found 2 minutes ago',
        );

        expect(exception.message, equals('Entry already exists'));
        expect(exception.field, equals('weight'));
        expect(exception.details, equals('Similar weight found 2 minutes ago'));
        expect(exception.type, equals(ValidationErrorType.duplicate));
        expect(exception.suggestedAction, contains('duplicate'));
      });

      test('should create range validation exception', () {
        final exception = ValidationException.range(
          field: 'weight',
          message: 'Weight must be between 20-300 kg',
          details: 'Current value: 500 kg',
        );

        expect(exception.message, equals('Weight must be between 20-300 kg'));
        expect(exception.field, equals('weight'));
        expect(exception.type, equals(ValidationErrorType.range));
        expect(exception.getUserFriendlyMessage(), contains('outside valid range'));
      });

      test('should create required field validation exception', () {
        final exception = ValidationException.required(field: 'systolic');

        expect(exception.message, equals('systolic is required'));
        expect(exception.field, equals('systolic'));
        expect(exception.type, equals(ValidationErrorType.required));
        expect(exception.getUserFriendlyMessage(), contains('Required field'));
      });

      test('should create business rule validation exception', () {
        final exception = ValidationException.businessRule(
          message: 'Systolic must be higher than diastolic',
          details: 'Current values: 90/100',
          suggestedAction: 'Please verify your blood pressure readings',
        );

        expect(exception.message, contains('Systolic must be higher'));
        expect(exception.type, equals(ValidationErrorType.businessRule));
        expect(exception.suggestedAction, contains('verify'));
      });
    });

    group('Enhanced Weight Validation', () {
      test('should validate weight with comprehensive error messages', () {
        final weightEntry = WeightEntry(
          weightKg: -5.0, // Invalid negative weight
          originalUnit: 'kg',
          timestamp: DateTime.now().add(Duration(days: 1)), // Future date
          notes: 'Test entry with invalid data',
        );

        final result = validationService.validateWeightEntry(weightEntry);

        expect(result.isValid, false);
        expect(result.errors, isNotEmpty);
        expect(result.errors.any((error) => error.contains('greater than 0')), true);
        expect(result.errors.any((error) => error.contains('future')), true);
      });

      test('should detect unusual weight changes', () {
        final oldWeight = 70.0; // kg
        final newWeight = 60.0; // kg - 10kg loss
        final oldDate = DateTime.now().subtract(Duration(days: 1));
        final newDate = DateTime.now();

        final result = validationService.validateWeightChange(
          oldWeight,
          newWeight,
          oldDate,
          newDate,
        );

        expect(result.warnings, isNotEmpty);
        expect(result.warnings.first, contains('Large weight change'));
      });

      test('should warn about extreme weight values', () {
        final extremeWeightEntry = WeightEntry(
          weightKg: 25.0, // Very low but technically valid
          originalUnit: 'kg',
          timestamp: DateTime.now(),
        );

        final result = validationService.validateWeightEntry(extremeWeightEntry);

        expect(result.isValid, true); // Should be valid but with warnings
        expect(result.warnings, isNotEmpty);
        expect(result.warnings.first, contains('very low'));
      });
    });

    group('Enhanced Blood Pressure Validation', () {
      test('should validate blood pressure with medical categories', () {
        final hypertensiveEntry = BloodPressureEntry(
          systolic: 200,
          diastolic: 120,
          timestamp: DateTime.now(),
        );

        final result = validationService.validateBloodPressureEntry(hypertensiveEntry);
        final categoryResult = validationService.validateBloodPressureCategory(200, 120);

        expect(result.isValid, true); // Values are valid numbers
        expect(categoryResult.warnings, isNotEmpty);
        expect(categoryResult.warnings.first, contains('CRITICAL'));
      });

      test('should detect invalid blood pressure relationships', () {
        final invalidBpEntry = BloodPressureEntry(
          systolic: 90,
          diastolic: 100, // Diastolic higher than systolic
          timestamp: DateTime.now(),
        );

        final result = validationService.validateBloodPressureEntry(invalidBpEntry);

        expect(result.isValid, false);
        expect(result.errors.any((error) => error.contains('higher than diastolic')), true);
      });

      test('should warn about unusual pulse pressure', () {
        final narrowPressureEntry = BloodPressureEntry(
          systolic: 105,
          diastolic: 100, // Only 5mmHg difference
          timestamp: DateTime.now(),
        );

        final result = validationService.validateBloodPressureEntry(narrowPressureEntry);

        expect(result.isValid, false); // Invalid due to systolic <= diastolic
        expect(result.warnings.isNotEmpty || result.errors.isNotEmpty, true);
      });
    });

    group('Enhanced Mood Validation', () {
      test('should validate mood entries with context suggestions', () {
        final moodEntry = MoodEntry(
          mood: MoodType.energized,
          timestamp: DateTime.now(),
          notes: null, // No notes
        );

        final result = validationService.validateMoodEntry(moodEntry);

        expect(result.isValid, true);
        expect(result.warnings, isNotEmpty);
        expect(result.warnings.first, contains('Consider adding notes'));
      });

      test('should validate mood with very long notes', () {
        final longNotes = 'This is a very long note that exceeds the recommended limit. ' * 20;
        final moodEntry = MoodEntry(
          mood: MoodType.stressed,
          timestamp: DateTime.now(),
          notes: longNotes,
        );

        final result = validationService.validateMoodEntry(moodEntry);

        expect(result.isValid, true); // Still valid but with warnings
        expect(result.warnings, isNotEmpty);
        expect(result.warnings.any((w) => w.contains('quite long')), true);
      });
    });

    group('Data Integrity Service', () {
      test('should perform comprehensive integrity check', () async {
        // This test would require actual database setup in a full implementation
        // For now, we test the structure and interface
        
        expect(dataIntegrityService.performIntegrityCheck, isA<Function>());
        expect(dataIntegrityService.cleanupOrphanedRecords, isA<Function>());
        expect(dataIntegrityService.mergeDuplicateEntries, isA<Function>());
      });
    });

    group('Error Handler Enhancement', () {
      test('should provide user-friendly error messages', () {
        final dbError = Exception('no such table: test');
        final appError = errorHandler.handleDatabaseError(dbError, operation: 'test');

        expect(appError.type, equals(ErrorType.database));
        expect(appError.code, contains('DB_'));
        
        final friendlyMessage = errorHandler.getUserFriendlyMessage(appError);
        expect(friendlyMessage, isNot(contains('no such table')));
        expect(friendlyMessage, isA<String>());
      });

      test('should provide recovery suggestions', () {
        final networkError = Exception('Connection refused');
        final appError = errorHandler.handleNetworkError(networkError);
        
        final suggestedAction = errorHandler.getSuggestedAction(appError);
        expect(suggestedAction, isNotNull);
        expect(suggestedAction, contains('connection'));
      });

      test('should determine if error is recoverable', () {
        final timeoutError = errorHandler.handleNetworkError(Exception('timeout'));
        final corruptDbError = errorHandler.handleDatabaseError(Exception('database is corrupted'));
        
        expect(errorHandler.isRecoverable(timeoutError), true);
        expect(errorHandler.isRecoverable(corruptDbError), false);
      });
    });

    group('Form Validation Integration', () {
      test('should validate required fields', () {
        final data = <String, dynamic>{'weight': null, 'date': DateTime.now()};
        final requiredFields = ['weight', 'date'];
        
        final result = validationService.validateRequiredFields(data, requiredFields);
        
        expect(result.isValid, false);
        expect(result.errors, contains('weight is required'));
      });

      test('should validate import data integrity', () {
        final invalidImportData = <String, dynamic>{
          'weight': [],
          'bloodPressure': [],
          'mood': [],
          // Missing version and exportDate
        };
        
        final result = validationService.validateImportData(invalidImportData);
        
        expect(result.warnings, isNotEmpty);
        expect(result.warnings.any((w) => w.contains('version')), true);
      });
    });

    group('Real-time Validation Feedback', () {
      test('should provide immediate validation feedback', () {
        // Test that validation occurs as user types
        const weight = -5.0;
        final validator = ValidatedNumberFieldValidators.weightValidator;
        
        final result = validator(weight);
        expect(result, isNotNull);
        expect(result!, contains('greater than 0'));
      });

      test('should provide range warnings for blood pressure', () {
        const systolic = 50.0; // Very low
        final validator = ValidatedNumberFieldValidators.bloodPressureValidator;
        
        final result = validator(systolic, isSystolic: true);
        expect(result, isNotNull);
        expect(result!, contains('too low'));
      });
    });
  });

  group('Widget Validation Integration', () {
    test('should validate date picker constraints', () {
      final futureDate = DateTime.now().add(Duration(days: 1));
      final validator = ValidatedDatePickerValidators.healthEntryDateValidator;
      
      final result = validator(futureDate);
      expect(result, isNotNull);
      expect(result!, contains('future'));
    });

    test('should validate date range limits', () {
      final veryOldDate = DateTime.now().subtract(Duration(days: 365 * 15));
      final validator = ValidatedDatePickerValidators.pastDateValidator;
      
      final result = validator(veryOldDate, maxYearsAgo: 10);
      expect(result, isNotNull);
      expect(result!, contains('10 years ago'));
    });
  });
}
