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_controller.dart';
import 'package:habitrack_app/infrastructure/widget_wall/items_state.dart';
import 'package:habitrack_app/main.dart';
import 'package:habitrack_app/sembast/tasks_list.dart';
import 'package:intl/intl.dart';

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

class TasksGraphWidget extends ConsumerStatefulWidget {
  TasksGraphWidget({super.key});

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

  final entries = <DataPoint>[
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
    DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
  ];
}

class _TasksGraphWidgetState extends ConsumerState<TasksGraphWidget> {
  void _buildList(List<dynamic> value) {
    final items = value;
    _tasksCompleted = 0;
    _tasksPlanned = 0;
    _weeklyOverdue = 0;
    _totalTasksCompleted = 0;
    _totalTasksPlanned = 0;
    _maxTasks = 0;
    _weeklyPlannedEntries = [];
    _weeklyOverdueEntries = [];
    _todayOverdue = 0;

    _totalOverdue = 0;
    const seperator = '_SEPARATOR_';

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

      _weeklyPlannedEntries.add(itemToInsert);
    }

    _weeklyWorkedEntries = [];

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

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

    for (final item in items) {
      if (_selectedValue == 'weekly' && item is TasksItem) {
        logger.i('HMM');

        _tasksCompleted = 0;

        for (final individualToDo in item.completedTaskList) {
          final toConvert = individualToDo.split(seperator);
          final parsedDate = DateTime.parse(toConvert.elementAtOrNull(2)!);

          var alreadyAdded = false;

          for (var i = 0; i <= 6; i++) {
            if (parsedDate.isBefore(_latestDate.subtract(Duration(days: i))) &&
                parsedDate
                    .isAfter(_latestDate.subtract(Duration(days: i + 1)))) {
              logger.i('LOOPING');
              if (!alreadyAdded) {
                alreadyAdded = true;
                _tasksCompleted += 1;
                _totalTasksCompleted += 1;
              }

              // Update maxAmount
              setState(() {
                logger.i('COMPLETED: $_tasksCompleted');
                _weeklyWorkedEntries.elementAt(6 - i).progress =
                    _tasksCompleted.toDouble();
                _weeklyPlannedEntries.elementAt(6 - i).progress =
                    _tasksPlanned.toDouble() +
                        _tasksCompleted.toDouble() +
                        _weeklyOverdue;
              });
            }
          }
        }
        _tasksPlanned = 0;
        _weeklyOverdue = 0;

        for (final individualToDo in item.taskList) {
          final toConvert = individualToDo.split(seperator);
          final due = DateTime.parse(toConvert.elementAtOrNull(1)!);

          final completedOn = DateTime.parse(toConvert.elementAtOrNull(3)!);

          final parsedDate = completedOn;

          var alreadyAdded = false;
          logger.i('NANI');

          for (var i = 0; i <= 6; i++) {
            if (parsedDate.isBefore(_latestDate.subtract(Duration(days: i))) &&
                parsedDate
                    .isAfter(_latestDate.subtract(Duration(days: i + 1)))) {
              logger.i('LOOPING');

              // Update maxAmount
              setState(() {
                if (!alreadyAdded) {
                  alreadyAdded = true;
                  final now = DateTime.now();
                  //   _maxTasks += 1;
                  if (DateTime(now.year, now.month, now.day).isAfter(due)) {
                    logger
                      ..i('OVERDUE TASK')
                      ..i('NOW: $now')
                      ..i('DUE: $due');
                    _totalOverdue += 1;
                    _weeklyOverdue += 1;
                    _weeklyOverdueEntries.elementAt(6 - i).progress =
                        _weeklyOverdue;
                  } else {
                    logger.i('Task is NOT overdue');
                    _tasksPlanned += 1;
                    _totalTasksPlanned += 1;
                  }
                }
                _weeklyPlannedEntries.elementAt(6 - i).progress =
                    _tasksPlanned.toDouble() +
                        _tasksCompleted.toDouble() +
                        _weeklyOverdue;
              });
            }
          }
          logger
            ..i('TASKS PLANNED FOR THIS DAY: $_tasksPlanned')
            ..i('TASKS COMPLETED FOR THIS DAY: $_tasksCompleted')
            ..i('TOTAL TASKS: ${_tasksPlanned + _tasksCompleted}');

          if (_tasksPlanned + _tasksCompleted + _weeklyOverdue > _maxTasks) {
            _maxTasks = (_tasksPlanned + _tasksCompleted + _weeklyOverdue)
                .ceilToDouble();
            logger.i('MAX TASKS: $_maxTasks');
          }
        }
      } else if (_selectedValue == 'daily' && item is TasksItem) {
        for (final individualToDo in item.completedTaskList) {
          final toConvert = individualToDo.split(seperator);

          final completedOn = DateTime.parse(toConvert.elementAtOrNull(3)!);

          final completed =
              toConvert.elementAtOrNull(4)!.toLowerCase() == 'true';

          final oneDayAgo = _latestDate.subtract(const Duration(days: 1));
          final parsedDate = completedOn;
          if (parsedDate.isBefore(oneDayAgo)) {
            logger.i('More than a day old');
          } else if (parsedDate.isAfter(oneDayAgo) &&
              parsedDate.isBefore(_latestDate)) {
            logger.i('TOday');
            if (completed) {
              _todayCompleted += 1;
              _todayPlanned += 1;
            } else {
              _todayPlanned += 1;
            }
          }
        }
        for (final individualToDo in item.taskList) {
          final toConvert = individualToDo.split(seperator);
          final due = DateTime.parse(toConvert.elementAtOrNull(1)!);

          final createdOn = DateTime.parse(toConvert.elementAtOrNull(2)!);

          final completed =
              toConvert.elementAtOrNull(4)!.toLowerCase() == 'true';

          final oneDayAgo = _latestDate.subtract(const Duration(days: 1));
          final parsedDate = createdOn;
          if (parsedDate.isBefore(oneDayAgo)) {
            logger.i('More than a day old');
          } else if (parsedDate.isAfter(oneDayAgo) &&
              parsedDate.isBefore(_latestDate)) {
            logger.i('TOday');
            if (completed) {
              _todayCompleted += 1;
              _todayPlanned += 1;
            } else {
              _todayPlanned += 1;
              final now = DateTime.now();
              if (DateTime(now.year, now.month, now.day).isAfter(due)) {
                logger
                  ..i('OVERDUE TASK')
                  ..i('NOW: $now')
                  ..i('DUE: $due');
                _totalOverdue += 1;
                _todayOverdue += 1;
              }
            }
          }
        }
      }
    }
  }

  void _showPreviousWeek() {
    if (_selectedValue == 'weekly') {
      _latestDate = _latestDate.subtract(const Duration(days: 7));
    } else if (_selectedValue == 'daily') {
      _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') {
      _latestDate = _latestDate.add(const Duration(days: 1));
    }
    if (!_latestDate.isAfter(DateTime.now())) {
      final items = ref.watch(itemsProvider);

      ref.watch(homeControllerProvider);
      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';
  }

  final gradientColors = [
    Colors.cyan,
    Colors.blueAccent,
  ];
  final gradient2Colors = [
    Colors.amber,
    Colors.amberAccent,
  ];
  final gradient3Colors = [
    Colors.deepPurple,
    Colors.deepPurpleAccent,
  ];
  List<dynamic> thisWeekItems = [];
  List<dynamic> todayItems = [];
  String? _selectedValue = 'weekly';

  int _tasksCompleted = 0;
  int _tasksPlanned = 0;
  int _totalTasksCompleted = 0;
  int _totalTasksPlanned = 0;
  double _maxTasks = 0;
  DateTime _latestDate = DateTime.now();
  double _todayCompleted = 0;
  double _todayPlanned = 0;
  double _todayOverdue = 0;
  double _weeklyOverdue = 0;
  double _totalOverdue = 0;

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

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

    // ignore: unused_element
    double getProgress() {
      if (_todayPlanned == 0) {
        return 0;
      }
      logger.i(
        'GLORIOUS PROGRESS${_todayCompleted / _todayPlanned}',
      );
      return _todayCompleted; // - this._todayCompleted;
    }

    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;
    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.elementAt(0).date, dataPoint.date)
              .toDouble();
      final lcbd = FlSpot(xValue, dataPoint.progress);

      weeklyWorkedSpots.add(lcbd);
    }

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

    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(
            // color: Theme.of(context).colorScheme.primaryContainer,
            padding:
                const EdgeInsets.only(bottom: 15, top: 15, right: 15, left: 5),
            child: SizedBox(
              width: MediaQuery.of(context).size.width * 0.9,
              height: MediaQuery.of(context).size.height * 0.5,
              child: LineChart(
                LineChartData(
                  minY: 0,
                  maxY: _maxTasks,
                  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(),
                        ),
                      ),
                    ),
                    LineChartBarData(
                      color: Colors.purple,
                      isCurved: true,
                      isStrokeCapRound: true,
                      preventCurveOverShooting: true,
                      spots: weeklyOverdueSpots,
                      belowBarData: BarAreaData(
                        show: true,
                        gradient: LinearGradient(
                          colors: gradient3Colors
                              .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: 50,
                        getTitlesWidget: (value, meta) => Text(
                          '${value.toInt()} task${value == 1 ? '' : 's'}',
                          style: const TextStyle(
                            fontSize: 10,
                            fontStyle: FontStyle.italic,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        interval: 1,
                      ),
                    ),
                    bottomTitles: AxisTitles(
                      sideTitles: SideTitles(
                        reservedSize: 30,
                        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,

                    // Cyan
                    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
                _getCompletedDescription() + _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') ? (_totalTasksPlanned + _totalTasksCompleted + _totalOverdue).toInt() : _todayPlanned.toInt()}${_getText()}',
              ),
              Text(
                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                      color: Theme.of(context).colorScheme.onPrimaryContainer,
                      fontSize: 15,
                      fontWeight: FontWeight.bold,
                    ),
                _getMissedDescription(),
              ),
            ],
          ),
        ),
      ],
    );
  }

  String _getCompletedDescription() {
    if (_selectedValue == 'weekly') {
      if (_totalTasksCompleted == 0) {
        return '0 tasks completed';
      } else if (_totalTasksCompleted == 1) {
        return '1 task completed';
      } else {
        return '$_totalTasksCompleted tasks completed';
      }
    } else if (_selectedValue == 'daily') {
      if (_todayCompleted == 0) {
        return '0 tasks completed';
      } else if (_todayCompleted == 1) {
        return '1 task completed';
      } else {
        return '${_todayCompleted.toInt()} tasks completed';
      }
    }
    return '';
  }

  String _getMissedDescription() {
    if (_selectedValue == 'weekly') {
      if (_totalOverdue == 0) {
        return 'No tasks were missed';
      } else if (_totalOverdue == 1) {
        return '1 task was missed';
      } else {
        return '${_totalOverdue.toInt()} tasks were missed';
      }
    } else if (_selectedValue == 'daily') {
      if (_todayOverdue == 0) {
        return 'No tasks were missed';
      } else if (_todayOverdue == 1) {
        return '1 task was missed';
      } else {
        return '${_todayOverdue.toInt()} tasks were missed';
      }
    }
    return '';
  }

  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();
  }
}
