import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:habitrack_app/infrastructure/widget_wall/items_state.dart';
import 'package:habitrack_app/main.dart';
import 'package:habitrack_app/sembast/hydration.dart';
import 'package:intl/intl.dart';

class DataPoint {
  DataPoint({required this.date, required this.progress});
  DateTime date;
  double progress;
}

class HydrationGraphWidget extends ConsumerStatefulWidget {
  const HydrationGraphWidget({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() =>
      _TasksGraphWidgetState();
}

class _TasksGraphWidgetState extends ConsumerState<HydrationGraphWidget> {
  void _buildList(List<dynamic> value) {
    final items = value;
    _thisWeekCompleted = 0;
    _thisWeekPlanned = 0;
    _maxAmount = 0;

    setState(() {
      _todayCompleted = 0;
      _todayPlanned = 0;
      _weeklyPlannedEntries = [];
      _weeklyWorkedEntries = [];
      for (var i = 0; i <= 6; i++) {
        final itemToInsert = DataPoint(
          date: _latestDate.subtract(Duration(days: 6 - i)),
          progress: 0,
        );

        _weeklyPlannedEntries.add(itemToInsert);
      }

      for (var i = 0; i <= 6; i++) {
        final itemToInsert = DataPoint(
          date: _latestDate.subtract(Duration(days: 6 - i)),
          progress: 0,
        );
        _weeklyWorkedEntries.add(itemToInsert);
      }
    });
    _thisWeekPlanned = 0;

    for (final item in items) {
      if (_selectedValue == 'weekly') {
        var alreadyAdded = false;
        for (var i = 0; i <= 6; i++) {
          DateTime parsedDate;

          if (item is Hydration) {
            if (item.current / item.goal >= 1 && item.completedOn != '') {
              //item is completed
              parsedDate = DateTime.parse(item.completedOn);
            } else {
              parsedDate = DateTime.parse(item.createdOn);
              logger.i('GOAL: $item.goal');
            }

            logger
                .i('BEFORE $i days ago and AFTER ${i + 1} days ago, element at '
                    'index ${6 - i} will be updated.');

            if (parsedDate.isBefore(_latestDate.subtract(Duration(days: i))) &&
                parsedDate
                    .isAfter(_latestDate.subtract(Duration(days: i + 1)))) {
              logger.i('LOOPING');
              if (!alreadyAdded) {
                alreadyAdded = true;
                _thisWeekCompleted += item.current / 1000;

                _thisWeekPlanned += item.goal / 1000;
              }

              if (item.goal > _maxAmount) {
                _maxAmount = (item.goal.toDouble() / 1000).ceilToDouble();
              }
              if (item.current > _maxAmount && item.current > item.goal) {
                _maxAmount = (item.current.toDouble() / 1000).ceilToDouble();
              }
              // Update maxAmount
              setState(() {
                _weeklyPlannedEntries.elementAt(6 - i).progress =
                    item.goal.toDouble() / 1000;
                _weeklyWorkedEntries.elementAt(6 - i).progress =
                    item.current.toDouble() / 1000;
              });
            }
          }
        }
      } else if (_selectedValue == 'daily' && item is Hydration) {
        logger.i('DATES');
        final parsedDate = DateTime.parse(item.createdOn);
        logger.i('LATEST DATE: $_latestDate');

        final oneDayAgo = _latestDate.subtract(const Duration(days: 1));

        if (parsedDate.isBefore(oneDayAgo)) {
          logger.i('More than a day old');
        } else if (parsedDate.isAfter(oneDayAgo) &&
            parsedDate.isBefore(_latestDate)) {
          logger.i('TOday');
          _todayCompleted = item.current / 1000;
          _todayPlanned = item.goal / 1000;
        }
      }
    }
  }

  void _showPreviousWeek() {
    setState(() {
      _todayPlanned = 0;
      _todayCompleted = 0;
      _thisWeekPlanned = 0;
      _thisWeekCompleted = 0;
    });

    if (_selectedValue == 'weekly') {
      _latestDate = _latestDate.subtract(const Duration(days: 7));
    } else if (_selectedValue == 'daily') {
      logger.i('HMMM');
      _latestDate = _latestDate.subtract(const Duration(days: 1));
    }
    final items = ref.watch(itemsProvider);

    switch (items) {
      case AsyncError(:final error):
        logger.i('Error: $error');
      case AsyncData(:final value):
        final allItems = value;

        _buildList(allItems);
      default:
        logger.i('Hmmm, how can we help?');
    } // get current date
    // show past 7 days starting 14 days ago
  }

  void _showNextWeek() {
    if (_selectedValue == 'weekly') {
      _latestDate = _latestDate.add(const Duration(days: 7));
    } else if (_selectedValue == 'daily') {
      logger.i('HMMM');
      _latestDate = _latestDate.add(const Duration(days: 1));
    }
    if (!_latestDate.isAfter(DateTime.now())) {
      final items = ref.watch(itemsProvider);

      switch (items) {
        case AsyncError(:final error):
          logger.i('Error: $error');
        case AsyncData(:final value):
          final allItems = value;

          _buildList(allItems);
        default:
          logger.i('Hmmm, how can we help?');
      } // get current date
    }

    // show past 7 days starting 14 days ago
  }

  String _getText() {
    final dateFormat = DateFormat('dd. MMM yyyy');

    if (_selectedValue == 'weekly' &&
        _latestDate.isAfter(DateTime.now().subtract(const Duration(days: 6)))) {
      return ' this past week';
    } else if (_selectedValue == 'weekly' &&
        !_latestDate
            .isAfter(DateTime.now().subtract(const Duration(days: 6)))) {
      return ' '
          'from'
          ' ${dateFormat.format(_latestDate.subtract(const Duration(days: 6)))}'
          ' to ${dateFormat.format(_latestDate)}';
    }
    final formattedDate = dateFormat.format(_latestDate);
    // return ' on ${_latestDate.toString().substring(6, 10)}';
    return ' on $formattedDate';
  }

  List<dynamic> thisWeekItems = [];
  List<dynamic> todayItems = [];
  String? _selectedValue = 'weekly';

  double _thisWeekCompleted = 0;
  double _thisWeekPlanned = 0;
  double _maxAmount = 0;
  DateTime _latestDate = DateTime.now();
  double _todayCompleted = 0;
  double _todayPlanned = 0;

  List<DataPoint> _weeklyPlannedEntries = <DataPoint>[];
  List<DataPoint> _weeklyWorkedEntries = <DataPoint>[];

  @override
  Widget build(BuildContext context) {
    final items = ref.watch(itemsProvider);

    switch (items) {
      case AsyncError(:final error):
        logger.i('Error: $error');
      case AsyncData(:final value):
        final allItems = value;
        _buildList(allItems);
      default:
        logger.i('Hmmm, how can we help?');
    }

    final firstDate = _weeklyPlannedEntries.elementAtOrNull(0)!.date;
    logger.i('HMMM $firstDate');
    final flSpots = <FlSpot>[];
    for (final dataPoint in _weeklyPlannedEntries) {
      final xValue = _daysBetween(_weeklyPlannedEntries[0].date, dataPoint.date)
          .toDouble();

      final lcbd = FlSpot(
        xValue,
        dataPoint.progress,
      );

      flSpots.add(lcbd);
    }

    final weeklyWorkedSpots = <FlSpot>[];
    for (final dataPoint in _weeklyWorkedEntries) {
      final xValue =
          _daysBetween(_weeklyWorkedEntries[0].date, dataPoint.date).toDouble();
      final lcbd = FlSpot(xValue, dataPoint.progress);

      weeklyWorkedSpots.add(lcbd);
    }
    final gradientColors = [
      Colors.cyan,
      Colors.blueAccent,
    ];
    final gradient2Colors = [
      Colors.amber,
      Colors.amberAccent,
    ];
    final df = DateFormat('dd. MMMM');

    return Column(
      children: [
        Container(
          height: 75,
          color: Theme.of(context).colorScheme.primaryContainer,
          margin: const EdgeInsets.only(bottom: 10),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton(
                onPressed: _showPreviousWeek,
                style: ButtonStyle(
                  shape: WidgetStateProperty.all(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),
                  ),
                ),
                child: const Text('Previous'),
              ),
              DropdownButton<String>(
                value: _selectedValue,
                borderRadius: BorderRadius.circular(10),
                onChanged: (value) {
                  setState(() {
                    _latestDate = DateTime.now();
                    _selectedValue = value;
                  });
                },
                items: const [
                  DropdownMenuItem(
                    value: 'daily',
                    child: Text('Daily'),
                  ),
                  DropdownMenuItem(
                    value: 'weekly',
                    child: Text('Weekly'),
                  ),
                ],
              ),
              ElevatedButton(
                onPressed: _showNextWeek,
                style: ButtonStyle(
                  shape: WidgetStateProperty.all(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),
                  ),
                ),
                child: const Text('Next'),
              ),
            ],
          ),
        ),
        if (_selectedValue == 'weekly') ...[
          Container(
            padding:
                const EdgeInsets.only(bottom: 15, top: 15, right: 15, left: 5),
            child: SizedBox(
              width: MediaQuery.of(context).size.width * 0.90,
              height: MediaQuery.of(context).size.height * 0.5,
              child: LineChart(
                LineChartData(
                  minY: 0,
                  maxY: _maxAmount,
                  lineBarsData: [
                    LineChartBarData(
                      isCurved: true,
                      preventCurveOverShooting: true,
                      spots: flSpots,
                      belowBarData: BarAreaData(
                        show: true,
                        gradient: LinearGradient(
                          colors: gradientColors
                              .map((color) => color.withOpacity(0.6))
                              .toList(),
                        ),
                      ),
                    ),
                    LineChartBarData(
                      color: Colors.amber,
                      isCurved: true,
                      isStrokeCapRound: true,
                      preventCurveOverShooting: true,
                      spots: weeklyWorkedSpots,
                      belowBarData: BarAreaData(
                        show: true,
                        gradient: LinearGradient(
                          colors: gradient2Colors
                              .map((color) => color.withOpacity(0.6))
                              .toList(),
                        ),
                      ),
                    ),
                  ],
                  titlesData: FlTitlesData(
                    rightTitles: const AxisTitles(
                      sideTitles: SideTitles(
                        reservedSize: 30,
                        interval: 20,
                      ),
                    ),
                    topTitles: const AxisTitles(
                      sideTitles: SideTitles(
                        interval: 20,
                      ),
                    ),
                    leftTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: true,
                        reservedSize: 30,
                        getTitlesWidget: (value, meta) => Text(
                          '$value l',
                          style: const TextStyle(
                            fontSize: 10,
                            fontStyle: FontStyle.italic,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        // interval: 0.25,
                      ),
                    ),
                    bottomTitles: AxisTitles(
                      sideTitles: SideTitles(
                        getTitlesWidget: (value, meta) => Text(
                          style: const TextStyle(
                            fontSize: 10,
                            fontStyle: FontStyle.italic,
                            fontWeight: FontWeight.bold,
                          ),
                          df.format(
                            DateTime(
                              firstDate.year,
                              firstDate.month,
                              firstDate.day,
                            ).add(Duration(days: value.round())),
                          ),
                        ),
                        showTitles: true,
                        interval: 1,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
        if (_selectedValue == 'daily') ...[
          SizedBox(
            width: MediaQuery.of(context).size.width * 0.90,
            height: MediaQuery.of(context).size.height * 0.5,
            child: PieChart(
              PieChartData(
                sectionsSpace: 0,
                sections: [
                  PieChartSectionData(
                    value: _todayCompleted, // Progress
                    color: Theme.of(context).colorScheme.primaryFixedDim,
                    radius: 60,
                    title: (_todayPlanned > 0)
                        // ignore: lines_longer_than_80_chars
                        ? '${((_todayCompleted / _todayPlanned) * 100).floorToDouble()} %'
                        : '0 %',

                    titleStyle: TextStyle(
                      fontSize: 15,
                      fontWeight: FontWeight.bold,
                      color: Theme.of(context).colorScheme.secondary,
                    ),
                  ),
                  PieChartSectionData(
                    titleStyle: TextStyle(
                      fontSize: 15,
                      fontWeight: FontWeight.bold,
                      color: Theme.of(context).colorScheme.primaryFixedDim,
                    ),
                    value: (_todayPlanned > 0 && _todayCompleted > 0)
                        ? (_todayPlanned - _todayCompleted)
                        : 1, // Total - progress
                    color: Theme.of(context).colorScheme.secondary,
                    radius: 60,
                    showTitle: _todayPlanned == 0 ||
                        (_todayPlanned > 0 && _todayCompleted == 0),
                    title: '0 %',
                  ),
                ],
              ),
            ),
          ),
        ],
        SizedBox(
          width: MediaQuery.of(context).size.width * 0.90,
          child: Column(
            children: [
              Text(
                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                      color: Theme.of(context).colorScheme.onPrimaryContainer,
                      fontSize: 15,
                      fontWeight: FontWeight.bold,
                    ),
                // ignore: lines_longer_than_80_chars
                '${(_selectedValue == 'weekly') ? _thisWeekCompleted : _todayCompleted} liters drunk${_getText()}',
              ),
              Text(
                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                      color: Theme.of(context).colorScheme.onPrimaryContainer,
                      fontSize: 15,
                      fontWeight: FontWeight.bold,
                    ),
                // ignore: lines_longer_than_80_chars
                'Out of a total goal of ${(_selectedValue == 'weekly') ? _thisWeekPlanned : _todayPlanned} liters',
              ),
            ],
          ),
        ),
      ],
    );
  }

  int _daysBetween(DateTime from, DateTime to) {
    final d1 = DateTime(from.year, from.month, from.day);
    final d2 = DateTime(to.year, to.month, to.day);
    return (d2.difference(d1).inHours / 24).round();
  }
}
