// ABOUTME: Blood pressure chart widget for visualizing BP data over time
// ABOUTME: Dual-line chart with color-coded zones and interactive data point selection

import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:albi/services/chart_data_service.dart';
import 'package:albi/utils/chart_utils.dart';
import 'package:albi/utils/blood_pressure_utils.dart';

/// Data structure for blood pressure chart points
class BPChartDataPoint {
  final DateTime timestamp;
  final int systolic;
  final int diastolic;
  final String? notes;
  final int? entryId;
  final String category;

  const BPChartDataPoint({
    required this.timestamp,
    required this.systolic,
    required this.diastolic,
    this.notes,
    this.entryId,
    required this.category,
  });

  double get meanArterialPressure => diastolic + ((systolic - diastolic) / 3);
  int get pulsePressure => systolic - diastolic;
}

/// Callback for BP data point interaction
typedef OnBPDataPointTapped = void Function(BPChartDataPoint? dataPoint);

/// Widget that displays blood pressure data as an interactive dual-line chart
class BPChart extends StatefulWidget {
  final List<BPChartDataPoint> data;
  final bool showCategoryZones;
  final bool enableInteraction;
  final OnBPDataPointTapped? onDataPointTapped;

  const BPChart({
    super.key,
    required this.data,
    this.showCategoryZones = true,
    this.enableInteraction = true,
    this.onDataPointTapped,
  });

  @override
  State<BPChart> createState() => _BPChartState();
}

class _BPChartState extends State<BPChart> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;
  int? _selectedPointIndex;
  ChartColorScheme? _colorScheme;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      duration: const Duration(milliseconds: 800),
      vsync: this,
    );
    _animation = CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    );
    _animationController.forward();
  }

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

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _colorScheme = ChartUtils.getColorScheme(Theme.of(context));
  }

  @override
  Widget build(BuildContext context) {
    if (widget.data.isEmpty || _colorScheme == null) {
      return _buildEmptyState(context);
    }

    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Semantics(
          label: 'Blood pressure chart showing systolic and diastolic readings over time',
          hint: 'Double tap to interact with data points',
          child: Container(
            padding: const EdgeInsets.all(16),
            child: AspectRatio(
              aspectRatio: ChartUtils.calculateAspectRatio(
                MediaQuery.of(context).size,
              ),
              child: LineChart(
                _createLineChartData(),
                duration: const Duration(milliseconds: 250),
              ),
            ),
          ),
        );
      },
    );
  }

  /// Build empty state when no data is available
  Widget _buildEmptyState(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(32),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.favorite,
            size: 64,
            color: Theme.of(context).colorScheme.primary.withOpacity(0.3),
          ),
          const SizedBox(height: 16),
          Text(
            'No blood pressure data available',
            style: Theme.of(context).textTheme.titleMedium?.copyWith(
              color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 8),
          Text(
            'Add blood pressure entries to see your health trends',
            style: Theme.of(context).textTheme.bodyMedium?.copyWith(
              color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5),
            ),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  /// Create the main line chart data configuration
  LineChartData _createLineChartData() {
    final data = widget.data;

    // Calculate axis bounds
    final systolicValues = data.map((p) => p.systolic.toDouble()).toList();
    final diastolicValues = data.map((p) => p.diastolic.toDouble()).toList();
    final allValues = [...systolicValues, ...diastolicValues];
    
    final minValue = allValues.reduce((a, b) => a < b ? a : b);
    final maxValue = allValues.reduce((a, b) => a > b ? a : b);
    
    // Add padding to the bounds
    final range = maxValue - minValue;
    final padding = range * 0.1;
    final adjustedMin = (minValue - padding).clamp(40, 300).toDouble();
    final adjustedMax = (maxValue + padding).clamp(40, 300).toDouble();

    // Calculate time span for axis formatting
    final timeSpan = data.isNotEmpty && data.length > 1
        ? data.last.timestamp.difference(data.first.timestamp)
        : const Duration(days: 7);

    return LineChartData(
      gridData: ChartUtils.createGridData(_colorScheme!),
      titlesData: FlTitlesData(
        show: true,
        topTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
        rightTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
        bottomTitles: AxisTitles(
          sideTitles: _createBottomTitles(data, timeSpan),
        ),
        leftTitles: AxisTitles(
          sideTitles: _createLeftTitles(adjustedMin, adjustedMax),
        ),
      ),
      borderData: ChartUtils.createBorderData(_colorScheme!),
      minX: 0,
      maxX: (data.length - 1).toDouble(),
      minY: adjustedMin,
      maxY: adjustedMax,
      lineBarsData: _createLineBarsData(),
      lineTouchData: _createTouchData(),
      clipData: const FlClipData.all(),
      // Add background color zones for BP categories if enabled
      extraLinesData: widget.showCategoryZones ? _createCategoryZones(adjustedMin, adjustedMax) : null,
    );
  }

  /// Create left axis titles for blood pressure values
  SideTitles _createLeftTitles(double minY, double maxY) {
    return SideTitles(
      showTitles: true,
      reservedSize: 50,
      interval: _calculateInterval(minY, maxY),
      getTitlesWidget: (value, meta) {
        return Text(
          value.toInt().toString(),
          style: TextStyle(
            color: _colorScheme!.axisColor,
            fontSize: 12,
          ),
        );
      },
    );
  }

  /// Create bottom axis titles for dates
  SideTitles _createBottomTitles(List<BPChartDataPoint> data, Duration timeSpan) {
    return ChartUtils.createBottomTitlesForDates(
      data.map((p) => p.timestamp).toList(),
      timeSpan,
    );
  }

  /// Calculate appropriate interval for Y-axis
  double _calculateInterval(double minY, double maxY) {
    final range = maxY - minY;
    if (range <= 20) return 5;
    if (range <= 50) return 10;
    if (range <= 100) return 20;
    return 50;
  }

  /// Create background color zones for blood pressure categories
  ExtraLinesData _createCategoryZones(double minY, double maxY) {
    final zones = <HorizontalLine>[];

    // Normal zone (below 120 systolic, below 80 diastolic)
    if (minY < 120) {
      zones.add(HorizontalLine(
        y: 120,
        color: Colors.green.withOpacity(0.1),
        strokeWidth: 2,
        dashArray: [5, 5],
      ));
    }

    // Elevated zone (120-129 systolic)
    if (minY < 130 && maxY > 120) {
      zones.add(HorizontalLine(
        y: 130,
        color: Colors.orange.withOpacity(0.1),
        strokeWidth: 2,
        dashArray: [5, 5],
      ));
    }

    // High Stage 1 (130-139 systolic, 80-89 diastolic)
    if (minY < 140 && maxY > 130) {
      zones.add(HorizontalLine(
        y: 140,
        color: Colors.orange.withOpacity(0.15),
        strokeWidth: 2,
        dashArray: [3, 3],
      ));
    }

    // High Stage 2 (140+ systolic, 90+ diastolic)
    if (maxY > 140) {
      zones.add(HorizontalLine(
        y: 180,
        color: Colors.red.withOpacity(0.1),
        strokeWidth: 2,
        dashArray: [10, 5],
      ));
    }

    return ExtraLinesData(horizontalLines: zones);
  }

  /// Create line bars data (systolic and diastolic lines)
  List<LineChartBarData> _createLineBarsData() {
    final lineBars = <LineChartBarData>[];
    final data = widget.data;

    // Systolic line (red)
    final systolicSpots = data.asMap().entries.map((entry) {
      return FlSpot(
        entry.key.toDouble(),
        entry.value.systolic.toDouble() * _animation.value,
      );
    }).toList();

    lineBars.add(LineChartBarData(
      spots: systolicSpots,
      isCurved: false,
      color: Colors.red,
      barWidth: 3,
      dotData: FlDotData(
        show: data.length <= 20,
        getDotPainter: (spot, percent, barData, index) {
          return FlDotCirclePainter(
            radius: 4,
            color: Colors.red,
            strokeWidth: 2,
            strokeColor: Colors.white,
          );
        },
      ),
      belowBarData: BarAreaData(show: false),
    ));

    // Diastolic line (blue)
    final diastolicSpots = data.asMap().entries.map((entry) {
      return FlSpot(
        entry.key.toDouble(),
        entry.value.diastolic.toDouble() * _animation.value,
      );
    }).toList();

    lineBars.add(LineChartBarData(
      spots: diastolicSpots,
      isCurved: false,
      color: Colors.blue,
      barWidth: 3,
      dotData: FlDotData(
        show: data.length <= 20,
        getDotPainter: (spot, percent, barData, index) {
          return FlDotCirclePainter(
            radius: 4,
            color: Colors.blue,
            strokeWidth: 2,
            strokeColor: Colors.white,
          );
        },
      ),
      belowBarData: BarAreaData(show: false),
    ));

    return lineBars;
  }

  /// Create touch interaction data
  LineTouchData _createTouchData() {
    if (!widget.enableInteraction) {
      return LineTouchData(enabled: false);
    }

    return LineTouchData(
      enabled: true,
      touchTooltipData: LineTouchTooltipData(
        getTooltipItems: (touchedSpots) {
          if (touchedSpots.isEmpty) return [];

          final index = touchedSpots.first.x.toInt();
          if (index >= 0 && index < widget.data.length) {
            final point = widget.data[index];
            
            return [
              LineTooltipItem(
                'Systolic: ${point.systolic} mmHg\n',
                const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
              ),
              LineTooltipItem(
                'Diastolic: ${point.diastolic} mmHg\n',
                const TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
              ),
              LineTooltipItem(
                point.category,
                TextStyle(
                  color: BloodPressureUtils.getCategoryColor(point.category),
                  fontWeight: FontWeight.w500,
                ),
              ),
            ];
          }
          return [];
        },
      ),
      touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
        if (event is FlTapUpEvent && response != null && response.lineBarSpots != null) {
          final index = response.lineBarSpots!.first.x.toInt();
          if (index >= 0 && index < widget.data.length) {
            setState(() => _selectedPointIndex = index);
            widget.onDataPointTapped?.call(widget.data[index]);
          }
        }
      },
      handleBuiltInTouches: true,
    );
  }
}
