import 'dart:math';
import '../models/models.dart';
import 'hazard_ratios.dart';
import 'mortality_tables.dart';

const String modelVersion = '1.1';

/// Maximum combined hazard ratio (prevents unrealistic compounding).
const double _maxCombinedHR = 4.0;

/// Damping factor for delta calculation (conservative estimate).
const double _dampingFactor = 0.3;

/// Uncertainty range multipliers (±20% around midpoint).
const double _lowMultiplier = 0.8;
const double _highMultiplier = 1.2;

/// Calculate combined hazard ratio from behavioral inputs.
double computeCombinedHazard(BehavioralInputs inputs, double bmi) {
  double hr = 1.0;

  // Screen 1 factors
  hr *= getSmokingHR(inputs.smoking, inputs.cigarettesPerDay);
  hr *= getAlcoholHR(inputs.alcohol);
  hr *= getSleepHR(inputs.sleepHours, inputs.sleepConsistent);
  hr *= getActivityHR(inputs.activity);
  hr *= getBmiHR(bmi);

  // Screen 2 factors
  hr *= getDietHR(inputs.diet);
  hr *= getProcessedFoodHR(inputs.processedFood);
  hr *= getDrugUseHR(inputs.drugUse);
  hr *= getSocialHR(inputs.social);
  hr *= getStressHR(inputs.stress);
  hr *= getDrivingHR(inputs.driving);
  hr *= getWorkHoursHR(inputs.workHours);

  return min(hr, _maxCombinedHR);
}

/// Calculate lifespan delta when modifying a behavior to optimal.
LifespanDelta _computeDelta(
  double baselineYears,
  double currentHR,
  double modifiedHR,
  String behaviorKey,
) {
  if (currentHR <= modifiedHR) {
    return LifespanDelta(
      lowMonths: 0,
      highMonths: 0,
      confidence: getConfidenceForBehavior(behaviorKey),
    );
  }

  final rawDeltaYears =
      baselineYears * (1 - modifiedHR / currentHR) * _dampingFactor;

  final midpointMonths = rawDeltaYears * 12;
  final lowMonths = (midpointMonths * _lowMultiplier).round();
  final highMonths = (midpointMonths * _highMultiplier).round();

  return LifespanDelta(
    lowMonths: max(0, lowMonths),
    highMonths: max(0, highMonths),
    confidence: getConfidenceForBehavior(behaviorKey),
  );
}

/// Get modified inputs with a specific behavior set to optimal.
BehavioralInputs _setToOptimal(BehavioralInputs inputs, String behaviorKey) {
  switch (behaviorKey) {
    case 'smoking':
      return inputs.copyWith(
        smoking: SmokingStatus.never,
        cigarettesPerDay: 0,
      );
    case 'alcohol':
      return inputs.copyWith(alcohol: AlcoholLevel.none);
    case 'sleep':
      return inputs.copyWith(sleepHours: 7.5, sleepConsistent: true);
    case 'activity':
      return inputs.copyWith(activity: ActivityLevel.high);
    case 'diet':
      return inputs.copyWith(diet: DietQuality.excellent);
    case 'processedFood':
      return inputs.copyWith(processedFood: ProcessedFoodLevel.rarely);
    case 'drugUse':
      return inputs.copyWith(drugUse: DrugUse.none);
    case 'social':
      return inputs.copyWith(social: SocialConnection.strong);
    case 'stress':
      return inputs.copyWith(stress: StressLevel.low);
    case 'driving':
      return inputs.copyWith(driving: DrivingExposure.low);
    case 'workHours':
      return inputs.copyWith(workHours: WorkHoursLevel.normal);
    default:
      return inputs;
  }
}

/// Check if a behavior is already at optimal level.
bool _isOptimal(BehavioralInputs inputs, String behaviorKey) {
  switch (behaviorKey) {
    case 'smoking':
      // Former smokers have already quit - no further action possible
      return inputs.smoking == SmokingStatus.never ||
          inputs.smoking == SmokingStatus.former;
    case 'alcohol':
      return inputs.alcohol == AlcoholLevel.none ||
          inputs.alcohol == AlcoholLevel.light;
    case 'sleep':
      return inputs.sleepHours >= 7 &&
          inputs.sleepHours <= 8 &&
          inputs.sleepConsistent;
    case 'activity':
      return inputs.activity == ActivityLevel.high;
    case 'diet':
      return inputs.diet == DietQuality.excellent;
    case 'processedFood':
      return inputs.processedFood == ProcessedFoodLevel.rarely;
    case 'drugUse':
      return inputs.drugUse == DrugUse.none;
    case 'social':
      return inputs.social == SocialConnection.strong;
    case 'stress':
      return inputs.stress == StressLevel.low;
    case 'driving':
      return inputs.driving == DrivingExposure.low;
    case 'workHours':
      return inputs.workHours == WorkHoursLevel.normal;
    default:
      return true;
  }
}

/// List of modifiable behavior keys.
const _modifiableBehaviors = [
  'smoking',
  'alcohol',
  'sleep',
  'activity',
  'diet',
  'processedFood',
  'drugUse',
  'social',
  'stress',
  'driving',
  'workHours',
];

/// Calculate ranked factors for a user profile and behavioral inputs.
CalculationResult calculateRankedFactors(
  UserProfile profile,
  BehavioralInputs inputs,
) {
  final baselineYears = getRemainingLifeExpectancy(
    profile.age,
    profile.sex,
    profile.country,
  );

  final conditionHR = getDiagnosisHR(profile.diagnoses);
  final adjustedBaselineYears = baselineYears / conditionHR;

  final currentHR = computeCombinedHazard(inputs, profile.bmi);

  final factors = <RankedFactor>[];

  for (final behaviorKey in _modifiableBehaviors) {
    if (_isOptimal(inputs, behaviorKey)) continue;

    final modifiedInputs = _setToOptimal(inputs, behaviorKey);
    final modifiedHR = computeCombinedHazard(modifiedInputs, profile.bmi);

    final delta = _computeDelta(
      adjustedBaselineYears,
      currentHR,
      modifiedHR,
      behaviorKey,
    );

    if (delta.highMonths >= 1) {
      factors.add(RankedFactor(
        behaviorKey: behaviorKey,
        displayName: getDisplayName(behaviorKey),
        delta: delta,
      ));
    }
  }

  factors.sort(
      (a, b) => b.delta.midpointMonths.compareTo(a.delta.midpointMonths));

  return CalculationResult(
    rankedFactors: factors,
    modelVersion: modelVersion,
    calculatedAt: DateTime.now(),
  );
}
