// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// totals_screen.dart
//
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nokken/src/core/ui/theme/app_colors.dart';
import 'package:nokken/src/core/ui/theme/app_text_styles.dart';
import 'package:nokken/src/core/ui/widgets/shared_widgets.dart';
import 'package:nokken/src/core/ui/widgets/timeframe_selector.dart';
import 'package:nokken/src/features/stats/models/stat_analysis.dart';
import 'package:nokken/src/features/mood_tracker/models/mood_entry.dart';
import 'package:nokken/src/features/mood_tracker/providers/mood_state.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_state.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_taken_provider.dart';
import 'package:nokken/src/features/bloodwork_tracker/providers/bloodwork_state.dart';
import 'package:nokken/src/features/medication_tracker/models/medication_dose.dart';

class TotalsScreen extends ConsumerStatefulWidget {
  final ComprehensiveAnalysis analysis;
  final String timeframe;

  const TotalsScreen({
    super.key,
    required this.analysis,
    required this.timeframe,
  });

  @override
  ConsumerState<TotalsScreen> createState() => _TotalsScreenState();
}

class _TotalsScreenState extends ConsumerState<TotalsScreen>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 5, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Health Data Totals'),
        bottom: TabBar(
          controller: _tabController,
          isScrollable: true,
          tabs: const [
            Tab(text: 'Mood & Emotions'),
            Tab(text: 'Health Factors'),
            Tab(text: 'Medications'),
            Tab(text: 'Appointments'),
            Tab(text: 'Hormones'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          _buildMoodEmotionsTab(),
          _buildHealthFactorsTab(),
          _buildMedicationsTab(),
          _buildAppointmentsTab(),
          _buildHormonesTab(),
        ],
      ),
    );
  }

  Widget _buildMoodEmotionsTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildSectionHeader('Mood Ratings', Colors.amber),
          SharedWidgets.verticalSpace(16),

          // Mood ratings table
          _buildTable(
            columns: ['Mood', 'Count', 'Percentage'],
            rows: _getMoodRows(),
            colors: [Colors.amber.withAlpha(20), Colors.amber.withAlpha(40)],
          ),

          SharedWidgets.verticalSpace(24),

          _buildSectionHeader('Emotions Tracked', Colors.pink),
          SharedWidgets.verticalSpace(16),

          // Emotions table
          _buildTable(
            columns: ['Emotion', 'Count', 'Percentage'],
            rows: _getEmotionRows(),
            colors: [Colors.pink.withAlpha(20), Colors.pink.withAlpha(40)],
          ),
        ],
      ),
    );
  }

  Widget _buildHealthFactorsTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildSectionHeader('Health Factors Tracked', Colors.teal),
          SharedWidgets.verticalSpace(16),

          // Health factors table
          _buildTable(
            columns: ['Factor', 'Records', 'Avg Value'],
            rows: _getHealthFactorRows(),
            colors: [Colors.teal.withAlpha(20), Colors.teal.withAlpha(40)],
          ),

          SharedWidgets.verticalSpace(24),

          _buildSectionHeader('Factor Relationships', Colors.purple),
          SharedWidgets.verticalSpace(16),

          // Relationships table
          _buildTable(
            columns: ['Factors', 'Strength', 'Type'],
            rows: _getRelationshipRows(),
            colors: [Colors.purple.withAlpha(20), Colors.purple.withAlpha(40)],
          ),
        ],
      ),
    );
  }

  Widget _buildMedicationsTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildSectionHeader('Medications Tracked', Colors.blue),
          SharedWidgets.verticalSpace(16),

          // Medications table
          _buildTable(
            columns: ['Medication', 'Doses', 'Adherence'],
            rows: _getMedicationRows(),
            colors: [Colors.blue.withAlpha(20), Colors.blue.withAlpha(40)],
          ),

          SharedWidgets.verticalSpace(24),

          _buildSectionHeader('Medication Impacts', Colors.indigo),
          SharedWidgets.verticalSpace(16),

          // Medication impacts table
          _buildTable(
            columns: ['Medication', 'Effect Strength', 'Days to Effect'],
            rows: _getMedicationImpactRows(),
            colors: [Colors.indigo.withAlpha(20), Colors.indigo.withAlpha(40)],
          ),
        ],
      ),
    );
  }

  Widget _buildAppointmentsTab() {
    final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
    final filteredRecords = TimeframeSelector.filterByTimeframe(
      items: bloodworkRecords,
      timeframe: widget.timeframe,
      getDate: (record) => record.date,
    );

    if (filteredRecords.isEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              Icons.event_note,
              size: 64,
              color: AppColors.secondary.withAlpha(120),
            ),
            SharedWidgets.verticalSpace(24),
            Text(
              'No Appointment Data',
              style: AppTextStyles.headlineSmall,
            ),
            SharedWidgets.verticalSpace(16),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 32.0),
              child: Text(
                'Start tracking your appointments to view statistics and analytics.',
                textAlign: TextAlign.center,
                style: AppTextStyles.bodyLarge,
              ),
            ),
          ],
        ),
      );
    }

    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildSectionHeader('Appointments Tracked', Colors.blue),
          SharedWidgets.verticalSpace(16),

          // Appointments table
          _buildTable(
            columns: ['Type', 'Count', 'Percentage'],
            rows: _getAppointmentRows(),
            colors: [Colors.blue.withAlpha(20), Colors.blue.withAlpha(40)],
          ),

          SharedWidgets.verticalSpace(24),

          _buildSectionHeader('Locations', Colors.teal),
          SharedWidgets.verticalSpace(16),

          // Locations table
          _buildTable(
            columns: ['Location', 'Visits', 'Percentage'],
            rows: _getLocationRows(),
            colors: [Colors.teal.withAlpha(20), Colors.teal.withAlpha(40)],
          ),
        ],
      ),
    );
  }

  Widget _buildHormonesTab() {
    final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
    final filteredRecords = TimeframeSelector.filterByTimeframe(
      items: bloodworkRecords,
      timeframe: widget.timeframe,
      getDate: (record) => record.date,
    );

    // Extract all hormone readings
    final allReadings = <String, List<double>>{};
    for (final record in filteredRecords) {
      for (final reading in record.hormoneReadings) {
        if (!allReadings.containsKey(reading.name)) {
          allReadings[reading.name] = [];
        }
        allReadings[reading.name]!.add(reading.value);
      }
    }

    if (allReadings.isEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              Icons.science,
              size: 64,
              color: AppColors.secondary.withAlpha(120),
            ),
            SharedWidgets.verticalSpace(24),
            Text(
              'No Hormone Data',
              style: AppTextStyles.headlineSmall,
            ),
            SharedWidgets.verticalSpace(16),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 32.0),
              child: Text(
                'Start tracking your hormone levels to view statistics and analytics.',
                textAlign: TextAlign.center,
                style: AppTextStyles.bodyLarge,
              ),
            ),
          ],
        ),
      );
    }

    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildSectionHeader('Hormone Levels Tracked', Colors.deepPurple),
          SharedWidgets.verticalSpace(16),

          // Hormones table
          _buildTable(
            columns: ['Hormone', 'Records', 'Avg Value', 'In Range'],
            rows: _getHormoneRows(),
            colors: [
              Colors.deepPurple.withAlpha(20),
              Colors.deepPurple.withAlpha(40)
            ],
          ),

          SharedWidgets.verticalSpace(24),

          _buildSectionHeader('Hormone Trends', Colors.purple),
          SharedWidgets.verticalSpace(16),

          // Hormone trends table
          _buildTable(
            columns: ['Hormone', 'Trend', 'Confidence'],
            rows: _getHormoneTrendRows(),
            colors: [Colors.purple.withAlpha(20), Colors.purple.withAlpha(40)],
          ),
        ],
      ),
    );
  }

  // Helper methods for building UI components

  Widget _buildSectionHeader(String title, Color color) {
    return Row(
      children: [
        Container(
          width: 4,
          height: 24,
          color: color,
        ),
        SharedWidgets.horizontalSpace(8),
        Text(
          title,
          style: AppTextStyles.titleMedium,
        ),
      ],
    );
  }

  Widget _buildTable({
    required List<String> columns,
    required List<List<String>> rows,
    required List<Color> colors,
  }) {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(color: AppColors.surfaceContainer),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        children: [
          // Header
          Container(
            padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
            decoration: BoxDecoration(
              color: colors[0],
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(8),
                topRight: Radius.circular(8),
              ),
            ),
            child: Row(
              children: columns.map((column) {
                return Expanded(
                  child: Text(
                    column,
                    style: AppTextStyles.bodyMedium.copyWith(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                );
              }).toList(),
            ),
          ),

          // Rows
          ...rows.asMap().entries.map((entry) {
            final index = entry.key;
            final row = entry.value;

            return Container(
              padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
              decoration: BoxDecoration(
                color: index % 2 == 0 ? colors[0] : colors[1],
                border: Border(
                  top: BorderSide(color: AppColors.surfaceContainer),
                ),
              ),
              child: Row(
                children: row.asMap().entries.map((cell) {
                  return Expanded(
                    child: Text(
                      cell.value,
                      style: AppTextStyles.bodyMedium,
                    ),
                  );
                }).toList(),
              ),
            );
          }),
        ],
      ),
    );
  }

  // Methods to generate data rows for tables

  List<List<String>> _getMoodRows() {
    // Get mood entries from the provider
    final moodEntries = ref.watch(moodEntriesProvider);
    final filteredEntries = TimeframeSelector.filterByTimeframe(
      items: moodEntries,
      timeframe: widget.timeframe,
      getDate: (entry) => entry.date,
    );

    if (filteredEntries.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Count occurrences of each mood rating
    final moodCounts = <MoodRating, int>{};
    for (final entry in filteredEntries) {
      moodCounts[entry.mood] = (moodCounts[entry.mood] ?? 0) + 1;
    }

    // Calculate total and percentages
    final totalEntries = filteredEntries.length;
    final rows = <List<String>>[];

    // Add rows for each mood rating
    for (final rating in MoodRating.values) {
      final count = moodCounts[rating] ?? 0;
      final percentage = totalEntries > 0 ? (count / totalEntries * 100) : 0;

      rows.add([
        rating.displayName,
        count.toString(),
        '${percentage.toStringAsFixed(1)}%',
      ]);
    }

    // Add total row
    rows.add([
      'Total',
      totalEntries.toString(),
      '100%',
    ]);

    return rows;
  }

  List<List<String>> _getEmotionRows() {
    // Get mood entries from the provider
    final moodEntries = ref.watch(moodEntriesProvider);
    final filteredEntries = TimeframeSelector.filterByTimeframe(
      items: moodEntries,
      timeframe: widget.timeframe,
      getDate: (entry) => entry.date,
    );

    if (filteredEntries.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Count occurrences of each emotion
    final emotionCounts = <Emotion, int>{};
    for (final entry in filteredEntries) {
      for (final emotion in entry.emotions) {
        emotionCounts[emotion] = (emotionCounts[emotion] ?? 0) + 1;
      }
    }

    // Calculate total emotions and percentages
    final totalEmotions = emotionCounts.values.fold(0, (a, b) => a + b);
    final rows = <List<String>>[];

    // Sort emotions by count (descending)
    final sortedEmotions = emotionCounts.entries.toList()
      ..sort((a, b) => b.value.compareTo(a.value));

    // Add rows for each emotion
    for (final entry in sortedEmotions) {
      final percentage =
          totalEmotions > 0 ? (entry.value / totalEmotions * 100) : 0;

      rows.add([
        entry.key.displayName,
        entry.value.toString(),
        '${percentage.toStringAsFixed(1)}%',
      ]);
    }

    return rows;
  }

  List<List<String>> _getHealthFactorRows() {
    // Get mood entries from the provider
    final moodEntries = ref.watch(moodEntriesProvider);
    final filteredEntries = TimeframeSelector.filterByTimeframe(
      items: moodEntries,
      timeframe: widget.timeframe,
      getDate: (entry) => entry.date,
    );

    if (filteredEntries.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Define the health factors with dynamic level tracking
    final healthFactors = <String, Map<String, dynamic>>{
      'Mood': {'count': 0, 'levels': <String, int>{}},
      'Sleep': {'count': 0, 'levels': <String, int>{}},
      'Energy': {'count': 0, 'levels': <String, int>{}},
      'Focus': {'count': 0, 'levels': <String, int>{}},
      'Appetite': {'count': 0, 'levels': <String, int>{}},
      'Dysphoria': {'count': 0, 'levels': <String, int>{}},
      'Exercise': {'count': 0, 'levels': <String, int>{}},
      'Libido': {'count': 0, 'levels': <String, int>{}},
    };

    // Process each mood entry
    for (final entry in filteredEntries) {
      // Process mood
      final moodName = entry.mood.displayName;
      healthFactors['Mood']!['count'] += 1;
      healthFactors['Mood']!['levels']![moodName] =
          (healthFactors['Mood']!['levels']![moodName] ?? 0) + 1;

      // Process sleep quality
      if (entry.sleepQuality != null) {
        final levelName = entry.sleepQuality!.displayName;
        healthFactors['Sleep']!['count'] += 1;
        healthFactors['Sleep']!['levels']![levelName] =
            (healthFactors['Sleep']!['levels']![levelName] ?? 0) + 1;
      }

      // Process energy level
      if (entry.energyLevel != null) {
        final levelName = entry.energyLevel!.displayName;
        healthFactors['Energy']!['count'] += 1;
        healthFactors['Energy']!['levels']![levelName] =
            (healthFactors['Energy']!['levels']![levelName] ?? 0) + 1;
      }

      // Process focus level
      if (entry.focusLevel != null) {
        final levelName = entry.focusLevel!.displayName;
        healthFactors['Focus']!['count'] += 1;
        healthFactors['Focus']!['levels']![levelName] =
            (healthFactors['Focus']!['levels']![levelName] ?? 0) + 1;
      }

      // Process appetite level
      if (entry.appetiteLevel != null) {
        final levelName = entry.appetiteLevel!.displayName;
        healthFactors['Appetite']!['count'] += 1;
        healthFactors['Appetite']!['levels']![levelName] =
            (healthFactors['Appetite']!['levels']![levelName] ?? 0) + 1;
      }

      // Process dysphoria level
      if (entry.dysphoriaLevel != null) {
        final levelName = entry.dysphoriaLevel!.displayName;
        healthFactors['Dysphoria']!['count'] += 1;
        healthFactors['Dysphoria']!['levels']![levelName] =
            (healthFactors['Dysphoria']!['levels']![levelName] ?? 0) + 1;
      }

      // Process exercise level
      if (entry.exerciseLevel != null) {
        final levelName = entry.exerciseLevel!.displayName;
        healthFactors['Exercise']!['count'] += 1;
        healthFactors['Exercise']!['levels']![levelName] =
            (healthFactors['Exercise']!['levels']![levelName] ?? 0) + 1;
      }

      // Process libido level
      if (entry.libidoLevel != null) {
        final levelName = entry.libidoLevel!.displayName;
        healthFactors['Libido']!['count'] += 1;
        healthFactors['Libido']!['levels']![levelName] =
            (healthFactors['Libido']!['levels']![levelName] ?? 0) + 1;
      }
    }

    // Generate table rows
    final rows = <List<String>>[];

    // Filter out factors with no data
    final factorsWithData = healthFactors.entries
        .where((factor) => factor.value['count'] > 0)
        .toList();

    // Sort factors by total count (descending)
    factorsWithData
        .sort((a, b) => b.value['count'].compareTo(a.value['count']));

    // Generate rows for each factor and its levels
    for (final factor in factorsWithData) {
      // Add main row for the factor
      rows.add([
        (factor.key),
        'Total: ${factor.value['count']}',
        '',
      ]);

      // Add sub-rows for each level
      final levels = factor.value['levels'] as Map<String, int>;

      // Sort levels by count (descending)
      final sortedLevels = levels.entries.toList()
        ..sort((a, b) => b.value.compareTo(a.value));

      for (final level in sortedLevels) {
        // Only add levels that have data
        if (level.value > 0) {
          // Calculate percentage
          final percentage =
              (level.value / factor.value['count'] * 100).toStringAsFixed(1);

          rows.add([
            '  - ${level.key}',
            level.value.toString(),
            '$percentage%',
          ]);
        }
      }
    }

    return rows.isNotEmpty
        ? rows
        : [
            ['No data', '-', '-']
          ];
  }

  List<List<String>> _getRelationshipRows() {
    final relationships = widget.analysis.relationships;
    // Sort by strength
    relationships.sort((a, b) => b.strength.compareTo(a.strength));

    // Convert to table rows
    if (relationships.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    return relationships.take(10).map((relationship) {
      return [
        relationship.factorNames.join(' & '),
        '${(relationship.strength * 100).toStringAsFixed(0)}%',
        relationship.type.name,
      ];
    }).toList();
  }

  List<List<String>> _getMedicationRows() {
    // Get medications and taken medication data
    final medications = ref.watch(medicationsProvider);
    final takenMeds = ref.watch(medicationTakenProvider);

    if (medications.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    final rows = <List<String>>[];

    // For each medication, calculate doses taken and adherence
    for (final medication in medications) {
      // Calculate expected doses within the timeframe
      final doseSchedules = <MedicationDose>[];

      // Get date range from timeframe
      final dateRange =
          TimeframeSelector.getDateRangeForTimeframe(widget.timeframe);
      if (dateRange == null) {
        continue;
      }

      // Generate all expected doses for the medication in the date range
      for (DateTime date = dateRange.start;
          !date.isAfter(dateRange.end);
          date = date.add(const Duration(days: 1))) {
        // Check if medication is due on this date
        if (medication.isDueOnDate(date)) {
          // Add a dose for each time slot
          for (int i = 0; i < medication.frequency; i++) {
            final timeSlot = i < medication.timeOfDay.length
                ? '${medication.timeOfDay[i].hour.toString().padLeft(2, '0')}:00'
                : i.toString();

            doseSchedules.add(MedicationDose(
              medicationId: medication.id,
              date: date,
              timeSlot: timeSlot,
            ));
          }
        }
      }

      // Count taken doses
      int takenCount = 0;
      for (final dose in doseSchedules) {
        if (takenMeds.contains(dose.toKey())) {
          takenCount++;
        }
      }

      // Calculate adherence
      final adherencePercentage = doseSchedules.isNotEmpty
          ? (takenCount / doseSchedules.length * 100)
          : 0.0;

      rows.add([
        medication.name,
        doseSchedules.length.toString(),
        '${adherencePercentage.toStringAsFixed(1)}%',
      ]);
    }

    // Sort by adherence (descending)
    rows.sort((a, b) {
      final aAdherence = double.tryParse(a[2].replaceAll('%', '')) ?? 0;
      final bAdherence = double.tryParse(b[2].replaceAll('%', '')) ?? 0;
      return bAdherence.compareTo(aAdherence);
    });

    return rows;
  }

  List<List<String>> _getMedicationImpactRows() {
    final impacts = widget.analysis.medicationImpacts;

    if (impacts.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Convert to table rows
    return impacts.map((impact) {
      return [
        impact.medicationName,
        '${(impact.effectStrength * 100).toStringAsFixed(0)}%',
        impact.daysToEffect.toString(),
      ];
    }).toList();
  }

  List<List<String>> _getAppointmentRows() {
    final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
    final filteredRecords = TimeframeSelector.filterByTimeframe(
      items: bloodworkRecords,
      timeframe: widget.timeframe,
      getDate: (record) => record.date,
    );

    if (filteredRecords.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Count by appointment type
    final typeCounts = <String, int>{};
    for (final record in filteredRecords) {
      final type = record.appointmentType.toString().split('.').last;
      typeCounts[type] = (typeCounts[type] ?? 0) + 1;
    }

    // Calculate total and percentages
    final totalAppointments = filteredRecords.length;
    final rows = <List<String>>[];

    for (final entry in typeCounts.entries) {
      final percentage = (entry.value / totalAppointments * 100);

      rows.add([
        entry.key,
        entry.value.toString(),
        '${percentage.toStringAsFixed(1)}%',
      ]);
    }

    // Add total row
    rows.add([
      'Total',
      totalAppointments.toString(),
      '100%',
    ]);

    return rows;
  }

  List<List<String>> _getLocationRows() {
    final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
    final filteredRecords = TimeframeSelector.filterByTimeframe(
      items: bloodworkRecords,
      timeframe: widget.timeframe,
      getDate: (record) => record.date,
    );

    if (filteredRecords.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Count by location
    final locationCounts = <String, int>{};
    for (final record in filteredRecords) {
      final location = record.location ?? 'Unknown';
      locationCounts[location] = (locationCounts[location] ?? 0) + 1;
    }

    // Calculate total and percentages
    final totalAppointments = filteredRecords.length;
    final rows = <List<String>>[];

    for (final entry in locationCounts.entries) {
      final percentage = (entry.value / totalAppointments * 100);

      rows.add([
        entry.key,
        entry.value.toString(),
        '${percentage.toStringAsFixed(1)}%',
      ]);
    }

    // Sort by count (descending)
    rows.sort((a, b) => int.parse(b[1]).compareTo(int.parse(a[1])));

    return rows;
  }

  List<List<String>> _getHormoneRows() {
    final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
    final filteredRecords = TimeframeSelector.filterByTimeframe(
      items: bloodworkRecords,
      timeframe: widget.timeframe,
      getDate: (record) => record.date,
    );

    if (filteredRecords.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Extract all hormone readings
    final hormoneData = <String, Map<String, dynamic>>{};
    for (final record in filteredRecords) {
      for (final reading in record.hormoneReadings) {
        if (!hormoneData.containsKey(reading.name)) {
          hormoneData[reading.name] = {
            'values': <double>[],
            'units': reading.unit,
            'min': reading.minValue,
            'max': reading.maxValue,
          };
        }

        // Add this reading's value
        hormoneData[reading.name]!['values'].add(reading.value);

        // Update min/max reference ranges if available
        if (reading.minValue != null &&
            hormoneData[reading.name]!['min'] == null) {
          hormoneData[reading.name]!['min'] = reading.minValue;
        }
        if (reading.maxValue != null &&
            hormoneData[reading.name]!['max'] == null) {
          hormoneData[reading.name]!['max'] = reading.maxValue;
        }
      }
    }

    // Generate table rows
    final rows = <List<String>>[];

    for (final entry in hormoneData.entries) {
      final values = entry.value['values'] as List<double>;
      final avgValue = values.reduce((a, b) => a + b) / values.length;
      final unit = entry.value['units'] as String;

      // Determine if in range
      final minValue = entry.value['min'] as double?;
      final maxValue = entry.value['max'] as double?;

      String inRange = '-';
      if (minValue != null && maxValue != null) {
        inRange = (avgValue >= minValue && avgValue <= maxValue) ? '✓' : '✗';
      }

      rows.add([
        entry.key,
        values.length.toString(),
        '${avgValue.toStringAsFixed(1)} $unit',
        inRange,
      ]);
    }

    // Sort by name
    rows.sort((a, b) => a[0].compareTo(b[0]));

    return rows;
  }

  List<List<String>> _getHormoneTrendRows() {
    final analyses = widget.analysis.hormoneAnalyses;

    if (analyses.isEmpty) {
      return [
        ['No data', '-', '-']
      ];
    }

    // Convert to table rows
    return analyses.map((hormone) {
      final trend = hormone.trend;
      return [
        hormone.hormoneName,
        trend.direction.name,
        '${(trend.strength * 100).toStringAsFixed(0)}%',
      ];
    }).toList();
  }
}
