// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// stat_analysis.dart
// Models for statistical analysis and visualization of health data
//
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:nokken/src/core/ui/theme/app_theme.dart';

/// Basic statistical models
class HealthCorrelation {
  final String factorName;
  final double correlation;
  final String? description;

  HealthCorrelation({
    required this.factorName,
    required this.correlation,
    this.description,
  });

  String get strengthDescription {
    final absCorr = correlation.abs();
    if (absCorr > 0.7) return 'Strong';
    if (absCorr > 0.5) return 'Moderate';
    if (absCorr > 0.3) return 'Weak';
    return 'Very weak';
  }

  String get directionDescription {
    if (correlation > 0) return 'positive';
    if (correlation < 0) return 'negative';
    return 'no';
  }

  Color get correlationColor {
    final absCorr = correlation.abs();
    if (absCorr > 0.7) return Colors.purple;
    if (absCorr > 0.5) return Colors.blue;
    if (absCorr > 0.3) return Colors.teal;
    return AppTheme.grey;
  }
}

enum TrendDirection {
  increasing,
  decreasing,
  none,
}

class HealthTrend {
  final String variableName;
  final TrendDirection direction;
  final double strength;
  final String? description;

  HealthTrend({
    required this.variableName,
    required this.direction,
    required this.strength,
    this.description,
  });

  String get strengthDescription {
    if (strength > 0.7) return 'Strong';
    if (strength > 0.5) return 'Moderate';
    if (strength > 0.3) return 'Weak';
    return 'Very weak';
  }

  Color get trendColor {
    switch (direction) {
      case TrendDirection.increasing:
        return Colors.green;
      case TrendDirection.decreasing:
        return Colors.red;
      case TrendDirection.none:
        return AppTheme.grey;
    }
  }

  IconData get trendIcon {
    switch (direction) {
      case TrendDirection.increasing:
        return Icons.trending_up;
      case TrendDirection.decreasing:
        return Icons.trending_down;
      case TrendDirection.none:
        return Icons.trending_flat;
    }
  }
}

class VariableStatistics {
  final String variableName;
  final double average;
  final double median;
  final double minimum;
  final double maximum;
  final double standardDeviation;

  VariableStatistics({
    required this.variableName,
    required this.average,
    required this.median,
    required this.minimum,
    required this.maximum,
    required this.standardDeviation,
  });
}

class StatisticalInsight {
  final String title;
  final String description;
  final double confidence; // 0-1 scale
  final List<HealthCorrelation>? correlations;
  final List<HealthTrend>? trends;
  final List<VariableStatistics>? statistics;

  StatisticalInsight({
    required this.title,
    required this.description,
    required this.confidence,
    this.correlations,
    this.trends,
    this.statistics,
  });

  Color get confidenceColor {
    if (confidence >= 0.8) return Colors.green;
    if (confidence >= 0.6) return Colors.blue;
    if (confidence >= 0.4) return Colors.amber;
    return AppTheme.grey;
  }

  String get confidenceDescription {
    if (confidence >= 0.8) return 'High confidence';
    if (confidence >= 0.6) return 'Medium confidence';
    if (confidence >= 0.4) return 'Lower confidence';
    return 'Low confidence';
  }
}

/// Represents a relationship between two or more health factors
class FactorRelationship {
  final List<String> factorNames;
  final double strength;
  final String description;
  final RelationshipType type;

  FactorRelationship({
    required this.factorNames,
    required this.strength,
    required this.description,
    required this.type,
  });

  String get strengthDescription {
    final absStrength = strength.abs();
    if (absStrength > 0.7) return 'Strong';
    if (absStrength > 0.5) return 'Moderate';
    if (absStrength > 0.3) return 'Weak';
    return 'Very weak';
  }

  Color get relationshipColor {
    final absStrength = strength.abs();
    if (absStrength > 0.7) return Colors.purple;
    if (absStrength > 0.5) return Colors.blue;
    if (absStrength > 0.3) return Colors.teal;
    return AppTheme.grey;
  }
}

/// Relationship types for multi-factor analysis
enum RelationshipType {
  correlation,
  causation,
  cluster,
  threshold,
  unknown,
}

/// Represents a pattern identified in the data
class HealthPattern {
  final String name;
  final String description;
  final double significance;
  final List<String> relatedFactors;
  final PatternType type;

  HealthPattern({
    required this.name,
    required this.description,
    required this.significance,
    required this.relatedFactors,
    required this.type,
  });

  Color get patternColor {
    if (significance > 0.7) return Colors.purple;
    if (significance > 0.5) return Colors.blue;
    if (significance > 0.3) return Colors.teal;
    return AppTheme.grey;
  }
}

/// Types of patterns that can be detected in health data
enum PatternType {
  trend,
  cyclical,
  cluster,
  anomaly,
  threshold,
  unknown,
}

/// Represents a prediction of future health metrics
class HealthPrediction {
  final String factorName;
  final double predictedValue;
  final double confidence;
  final String description;
  final DateTime targetDate;

  HealthPrediction({
    required this.factorName,
    required this.predictedValue,
    required this.confidence,
    required this.description,
    required this.targetDate,
  });

  Color get confidenceColor {
    if (confidence > 0.7) return Colors.green;
    if (confidence > 0.5) return Colors.blue;
    if (confidence > 0.3) return Colors.amber;
    return AppTheme.grey;
  }

  /// Get a user-friendly confidence description
  String get confidenceDescription {
    if (confidence >= 0.8) {
      return 'Very High';
    } else if (confidence >= 0.6) {
      return 'High';
    } else if (confidence >= 0.4) {
      return 'Moderate';
    } else if (confidence >= 0.2) {
      return 'Low';
    } else {
      return 'Very Low';
    }
  }

  /// Format target date
  String get formattedTargetDate => DateFormat('MMMM d').format(targetDate);

  /// Format target date (short)
  String get shortFormattedTargetDate => DateFormat('MMM d').format(targetDate);
}

/// Represents an anomaly or unusual data point
class HealthAnomaly {
  final DateTime date;
  final String factorName;
  final double anomalyScore;
  final String description;
  final List<String>? possibleCauses;

  HealthAnomaly({
    required this.date,
    required this.factorName,
    required this.anomalyScore,
    required this.description,
    this.possibleCauses,
  });

  Color get anomalyColor {
    if (anomalyScore > 0.7) return Colors.red;
    if (anomalyScore > 0.5) return Colors.orange;
    if (anomalyScore > 0.3) return Colors.amber;
    return AppTheme.grey;
  }

  /// Get formatted date string
  String get formattedDate => DateFormat('MMM d').format(date);
}

/// Represents the impact ranking of different factors on a target variable
class FactorImpactRanking {
  final String targetFactor;
  final List<RankedFactor> impactingFactors;
  final String description;

  FactorImpactRanking({
    required this.targetFactor,
    required this.impactingFactors,
    required this.description,
  });
}

class RankedFactor {
  final String name;
  final double impactScore;
  final String description;

  RankedFactor({
    required this.name,
    required this.impactScore,
    required this.description,
  });

  Color get impactColor {
    if (impactScore > 0.7) return Colors.purple;
    if (impactScore > 0.5) return Colors.blue;
    if (impactScore > 0.3) return Colors.teal;
    return AppTheme.grey;
  }

  String get impactDescription {
    if (impactScore > 0.7) return 'Very high impact';
    if (impactScore > 0.5) return 'High impact';
    if (impactScore > 0.3) return 'Moderate impact';
    return 'Low impact';
  }
}

/// Represents a set of health metrics across days of the week
class WeekdayAnalysis {
  final Map<String, List<double>> factorsByWeekday;
  final Map<String, int> bestDays;
  final Map<String, int> worstDays;
  final String description;

  WeekdayAnalysis({
    required this.factorsByWeekday,
    required this.bestDays,
    required this.worstDays,
    required this.description,
  });

  /// Get day name from day index (1-7)
  String getDayName(int weekday) {
    switch (weekday) {
      case 1:
        return 'Monday';
      case 2:
        return 'Tuesday';
      case 3:
        return 'Wednesday';
      case 4:
        return 'Thursday';
      case 5:
        return 'Friday';
      case 6:
        return 'Saturday';
      case 7:
        return 'Sunday';
      default:
        return 'Unknown';
    }
  }

  /// Get short day name from day index (1-7)
  String getShortDayName(int dayIndex) {
    final shortDayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

    // Ensure dayIndex is valid
    if (dayIndex < 1 || dayIndex > 7) {
      return 'Unk';
    }

    return shortDayNames[dayIndex - 1];
  }

  /// Calculate average value for a specific factor on a specific day
  double getFactorAverage(String factor, int dayIndex) {
    final dayData = factorsByWeekday['$factor-$dayIndex'] ?? [];

    if (dayData.isEmpty) {
      return 0.0;
    }

    return dayData.reduce((a, b) => a + b) / dayData.length;
  }
}

/// Represents a streak or consistent period for a health metric
class HealthStreak {
  final String factorName;
  final int streakLength;
  final DateTime startDate;
  final DateTime endDate;
  final StreakType type;
  final String description;

  HealthStreak({
    required this.factorName,
    required this.streakLength,
    required this.startDate,
    required this.endDate,
    required this.type,
    required this.description,
  });

  Color get streakColor {
    switch (type) {
      case StreakType.positive:
        return Colors.green;
      case StreakType.negative:
        return Colors.red;
      case StreakType.neutral:
        return Colors.amber;
      case StreakType.consistent:
        return Colors.blue;
    }
  }
}

enum StreakType {
  positive,
  negative,
  neutral,
  consistent,
}

/// Represents hormone level analysis
class HormoneAnalysis {
  final String hormoneName;
  final double averageLevel;
  final double optimalMinLevel;
  final double optimalMaxLevel;
  final HealthTrend trend;
  final List<FactorRelationship> relationships;
  final String description;

  HormoneAnalysis({
    required this.hormoneName,
    required this.averageLevel,
    required this.optimalMinLevel,
    required this.optimalMaxLevel,
    required this.trend,
    required this.relationships,
    required this.description,
  });

  bool get isWithinOptimalRange {
    return averageLevel >= optimalMinLevel && averageLevel <= optimalMaxLevel;
  }

  Color get levelColor {
    if (isWithinOptimalRange) return Colors.green;
    if (averageLevel < optimalMinLevel) return Colors.orange;
    return Colors.red;
  }
}

/// Represents medication impact analysis
class MedicationImpact {
  final String medicationName;
  final Map<String, double> beforeAfterChanges;
  final int daysToEffect;
  final double effectStrength;
  final String description;

  MedicationImpact({
    required this.medicationName,
    required this.beforeAfterChanges,
    required this.daysToEffect,
    required this.effectStrength,
    required this.description,
  });

  Color get impactColor {
    if (effectStrength > 0.7) return Colors.purple;
    if (effectStrength > 0.5) return Colors.blue;
    if (effectStrength > 0.3) return Colors.teal;
    return AppTheme.grey;
  }
}

/// Comprehensive analysis object containing all types of insights
class ComprehensiveAnalysis {
  final List<StatisticalInsight> generalInsights;
  final List<FactorRelationship> relationships;
  final List<HealthPattern> patterns;
  final List<HealthPrediction> predictions;
  final List<HealthAnomaly> anomalies;
  final List<FactorImpactRanking> factorRankings;
  final WeekdayAnalysis? weekdayAnalysis;
  final List<HealthStreak> streaks;
  final List<HormoneAnalysis> hormoneAnalyses;
  final List<MedicationImpact> medicationImpacts;
  final TrendAnalysis moodTrend;
  final DateTime analysisDate;
  final String timeframe;

  ComprehensiveAnalysis({
    required this.generalInsights,
    required this.relationships,
    required this.patterns,
    required this.predictions,
    required this.anomalies,
    required this.factorRankings,
    this.weekdayAnalysis,
    required this.streaks,
    required this.hormoneAnalyses,
    required this.medicationImpacts,
    required this.moodTrend,
    required this.analysisDate,
    required this.timeframe,
  });

  // Helper to get all factor names
  Set<String> get allFactorNames {
    final factors = <String>{};

    // Add from relationships
    for (final rel in relationships) {
      factors.addAll(rel.factorNames);
    }

    // Add from patterns
    for (final pattern in patterns) {
      factors.addAll(pattern.relatedFactors);
    }

    // Add from predictions
    for (final pred in predictions) {
      factors.add(pred.factorName);
    }

    // Add from anomalies
    for (final anomaly in anomalies) {
      factors.add(anomaly.factorName);
    }

    // Add from factor rankings
    for (final ranking in factorRankings) {
      factors.add(ranking.targetFactor);
      for (final factor in ranking.impactingFactors) {
        factors.add(factor.name);
      }
    }

    // Add from streaks
    for (final streak in streaks) {
      factors.add(streak.factorName);
    }

    // Add from hormone analyses
    for (final hormone in hormoneAnalyses) {
      factors.add(hormone.hormoneName);
    }

    return factors;
  }

  // Get analysis for a specific factor
  Map<String, dynamic> getFactorAnalysis(String factorName) {
    final result = <String, dynamic>{
      'relationships': relationships
          .where((r) => r.factorNames.contains(factorName))
          .toList(),
      'patterns':
          patterns.where((p) => p.relatedFactors.contains(factorName)).toList(),
      'predictions':
          predictions.where((p) => p.factorName == factorName).toList(),
      'anomalies': anomalies.where((a) => a.factorName == factorName).toList(),
      'factorRankings': factorRankings
          .where((r) =>
              r.targetFactor == factorName ||
              r.impactingFactors.any((f) => f.name == factorName))
          .toList(),
      'streaks': streaks.where((s) => s.factorName == factorName).toList(),
      'hormoneAnalyses':
          hormoneAnalyses.where((h) => h.hormoneName == factorName).toList(),
      'medicationImpacts': medicationImpacts
          .where((m) =>
              m.medicationName == factorName ||
              m.beforeAfterChanges.containsKey(factorName))
          .toList(),
    };

    return result;
  }
}

// Original TrendType from health_analytics_service
// Kept for compatibility
enum TrendType {
  none(0),
  increasing(1),
  decreasing(2),
  cyclic(3),
  variable(4);

  final int value;
  const TrendType(this.value);
}

// Original TrendAnalysis from health_analytics_service
// Kept for compatibility
class TrendAnalysis {
  final TrendType type;
  final double strength;
  final String description;

  TrendAnalysis({
    required this.type,
    required this.strength,
    required this.description,
  });
}
