import 'package:flutter_test/flutter_test.dart';
import 'package:add_months/models/models.dart';
import 'package:add_months/risk_engine/risk_engine.dart';

void main() {
  group('Hazard Ratios', () {
    test('smoking current produces HR > 1.8', () {
      expect(getSmokingHR(SmokingStatus.current, 10), greaterThanOrEqualTo(1.8));
    });

    test('smoking heavy (>20/day) produces highest HR', () {
      final lightHR = getSmokingHR(SmokingStatus.current, 5);
      final moderateHR = getSmokingHR(SmokingStatus.current, 15);
      final heavyHR = getSmokingHR(SmokingStatus.current, 25);

      expect(heavyHR, greaterThan(moderateHR));
      expect(moderateHR, greaterThan(lightHR));
      expect(heavyHR, equals(2.8));
    });

    test('never smoker has HR of 1.0', () {
      expect(getSmokingHR(SmokingStatus.never, 0), equals(1.0));
    });

    test('sedentary activity has higher HR than active', () {
      expect(
        getActivityHR(ActivityLevel.sedentary),
        greaterThan(getActivityHR(ActivityLevel.high)),
      );
    });

    test('very heavy alcohol has highest HR', () {
      expect(getAlcoholHR(AlcoholLevel.veryHeavy), equals(1.6));
      expect(getAlcoholHR(AlcoholLevel.none), equals(1.0));
    });

    test('short sleep has higher HR than optimal', () {
      expect(getSleepHR(5.0, true), greaterThan(getSleepHR(7.5, true)));
    });

    test('inconsistent sleep adds to HR', () {
      expect(getSleepHR(7.0, false), greaterThan(getSleepHR(7.0, true)));
    });
  });

  group('Mortality Tables', () {
    test('Japan is in Group A', () {
      expect(getCountryGroup('Japan'), equals(MortalityGroup.groupA));
    });

    test('United States is in Group B', () {
      expect(getCountryGroup('United States'), equals(MortalityGroup.groupB));
    });

    test('female LE is higher than male', () {
      final maleLE =
          getLifeExpectancyAtBirth(MortalityGroup.groupB, Sex.male);
      final femaleLE =
          getLifeExpectancyAtBirth(MortalityGroup.groupB, Sex.female);

      expect(femaleLE, greaterThan(maleLE));
    });

    test('remaining LE decreases with age', () {
      final le30 = getRemainingLifeExpectancy(30, Sex.male, 'United States');
      final le50 = getRemainingLifeExpectancy(50, Sex.male, 'United States');

      expect(le30, greaterThan(le50));
    });

    test('getSupportedCountries returns sorted list', () {
      final countries = getSupportedCountries();
      expect(countries, isNotEmpty);
      expect(countries.first, equals('Argentina'));
      expect(countries, contains('United States'));
    });
  });

  group('Calculator', () {
    final healthyProfile = UserProfile(
      age: 40,
      sex: Sex.male,
      country: 'United States',
      heightCm: 175,
      weightKg: 75,
    );

    final optimalInputs = BehavioralInputs.optimal;

    final unhealthyInputs = BehavioralInputs(
      smoking: SmokingStatus.current,
      cigarettesPerDay: 20,
      alcohol: AlcoholLevel.heavy,
      sleepHours: 5.0,
      sleepConsistent: false,
      activity: ActivityLevel.sedentary,
      diet: DietQuality.poor,
      processedFood: ProcessedFoodLevel.daily,
      drugUse: DrugUse.regular,
      social: SocialConnection.isolated,
      stress: StressLevel.chronic,
      driving: DrivingExposure.veryHigh,
      workHours: WorkHoursLevel.extreme,
    );

    test('optimal inputs produce low combined HR', () {
      final hr = computeCombinedHazard(optimalInputs, 22.0);
      expect(hr, closeTo(1.0, 0.1));
    });

    test('unhealthy inputs produce high combined HR', () {
      final hr = computeCombinedHazard(unhealthyInputs, 35.0);
      expect(hr, greaterThan(3.0));
    });

    test('combined HR is capped at 4.0', () {
      final hr = computeCombinedHazard(unhealthyInputs, 45.0);
      expect(hr, lessThanOrEqualTo(4.0));
    });

    test('ranking puts smoking above driving for heavy smoker', () {
      final smokerInputs = BehavioralInputs(
        smoking: SmokingStatus.current,
        cigarettesPerDay: 20,
        alcohol: AlcoholLevel.none,
        sleepHours: 7.5,
        sleepConsistent: true,
        activity: ActivityLevel.high,
        diet: DietQuality.excellent,
        processedFood: ProcessedFoodLevel.rarely,
        drugUse: DrugUse.none,
        social: SocialConnection.strong,
        stress: StressLevel.low,
        driving: DrivingExposure.veryHigh,
        workHours: WorkHoursLevel.normal,
      );

      final result = calculateRankedFactors(healthyProfile, smokerInputs);

      expect(result.rankedFactors, isNotEmpty);
      expect(result.dominantFactor?.behaviorKey, equals('smoking'));
    });

    test('optimal profile returns empty factors', () {
      final result = calculateRankedFactors(healthyProfile, optimalInputs);
      expect(result.rankedFactors, isEmpty);
    });

    test('result includes model version', () {
      final result = calculateRankedFactors(healthyProfile, unhealthyInputs);
      expect(result.modelVersion, equals('1.1'));
    });

    test('sedentary person sees activity as factor', () {
      final sedentaryInputs = BehavioralInputs(
        smoking: SmokingStatus.never,
        cigarettesPerDay: 0,
        alcohol: AlcoholLevel.none,
        sleepHours: 7.5,
        sleepConsistent: true,
        activity: ActivityLevel.sedentary,
        diet: DietQuality.excellent,
        processedFood: ProcessedFoodLevel.rarely,
        drugUse: DrugUse.none,
        social: SocialConnection.strong,
        stress: StressLevel.low,
        driving: DrivingExposure.low,
        workHours: WorkHoursLevel.normal,
      );

      final result = calculateRankedFactors(healthyProfile, sedentaryInputs);

      expect(result.rankedFactors, isNotEmpty);
      expect(result.dominantFactor?.behaviorKey, equals('activity'));
    });

    test('delta ranges are reasonable', () {
      final result = calculateRankedFactors(healthyProfile, unhealthyInputs);

      for (final factor in result.rankedFactors) {
        // Low should be less than or equal to high
        expect(factor.delta.lowMonths, lessThanOrEqualTo(factor.delta.highMonths));
        // Months should be reasonable (not hundreds of years)
        expect(factor.delta.highMonths, lessThan(240)); // < 20 years
      }
    });
  });

  group('Existing Conditions', () {
    test('cardiovascular disease increases diagnosis HR', () {
      final hr = getDiagnosisHR({Diagnosis.cardiovascular});
      expect(hr, equals(1.5));
    });

    test('multiple conditions compound', () {
      final singleHR = getDiagnosisHR({Diagnosis.diabetes});
      final multiHR = getDiagnosisHR({Diagnosis.diabetes, Diagnosis.hypertension});

      expect(multiHR, greaterThan(singleHR));
    });

    test('conditions reduce effective baseline', () {
      final healthyProfile = UserProfile(
        age: 50,
        sex: Sex.male,
        country: 'United States',
        heightCm: 175,
        weightKg: 80,
        diagnoses: {},
      );

      final unhealthyProfile = healthyProfile.copyWith(
        diagnoses: {Diagnosis.cardiovascular, Diagnosis.diabetes},
      );

      final sedentaryInputs = BehavioralInputs(
        smoking: SmokingStatus.never,
        cigarettesPerDay: 0,
        alcohol: AlcoholLevel.none,
        sleepHours: 7.5,
        sleepConsistent: true,
        activity: ActivityLevel.sedentary,
        diet: DietQuality.excellent,
        processedFood: ProcessedFoodLevel.rarely,
        drugUse: DrugUse.none,
        social: SocialConnection.strong,
        stress: StressLevel.low,
        driving: DrivingExposure.low,
        workHours: WorkHoursLevel.normal,
      );

      final healthyResult = calculateRankedFactors(healthyProfile, sedentaryInputs);
      final unhealthyResult = calculateRankedFactors(unhealthyProfile, sedentaryInputs);

      // Unhealthy person has less to gain (lower baseline)
      if (healthyResult.dominantFactor != null && unhealthyResult.dominantFactor != null) {
        expect(
          unhealthyResult.dominantFactor!.delta.highMonths,
          lessThan(healthyResult.dominantFactor!.delta.highMonths),
        );
      }
    });
  });
}
