import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:tasktracker/AvgDay.dart';
import 'package:tasktracker/main.dart';

import 'Data.dart';
import 'DebugHelper.dart';
import 'User.dart' as User;

class AnalyticsPage extends StatefulWidget {
  const AnalyticsPage({Key? key}) : super(key: key);

  @override
  State<AnalyticsPage> createState() => _AnalyticsPageState();
}

class _AnalyticsPageState extends State<AnalyticsPage> {



  @override
  Widget build(BuildContext context) {
    List<Activity> avgDayActs = AnalyticTools.getAverageDayActs(DateTimeRange(start: DateTime.now().subtract(Duration(days:7)),end: DateTime.now()));
    List<CatMapData> avgDayData =[];
    Map<Category, int> avgTime = <Category,int>{};

    for (var act in avgDayActs) {
      if(avgTime.containsKey(act.taskType.cat!)){
        int _val = avgTime[act.taskType.cat!]!;
        avgTime.update(act.taskType.cat!, (value) => _val + act.endTime.difference(act.startTime).inMinutes);
      }else{
        avgTime.putIfAbsent(act.taskType.cat!, () => act.endTime.difference(act.startTime).inMinutes);
      }
    }
    int trackedTime = 0;
    avgTime.forEach((key, value) {
      avgDayData.add(CatMapData(key.name, value, HexColor.fromHex(key.color)));
      trackedTime+= value;
    });

    avgDayData.add(CatMapData('Untracked', 1440-trackedTime, Colors.black));
    // for (var value in avgActs) {
    //   Debug.LogResponse('${value.taskType.name} : ${DateFormat('HH:mm').format(value.startTime)} - ${DateFormat('HH:mm').format(value.endTime)}');
    // }
    bool landscape=((MediaQuery.of(context).size.width / MediaQuery.of(context).size.height) > 1);
    return Scaffold(
      appBar: AppBar(title: Row(
        children: [FaIcon(FontAwesomeIcons.chartLine),SizedBox(width: 15,), Text("Analytics")],
      )),
      drawer: landscape ? null : navDrawer(context, 1),
      body: Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          landscape?navDrawer(context, 1) : Container(),
          Expanded(
            child: Align(
              alignment: Alignment.topCenter ,
              child: SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: Container(
                  padding: EdgeInsets.all(8),
                  child:Column(
                    children: [
                      Card(
                        child: Container(
                          padding: EdgeInsets.symmetric(horizontal: 15, vertical: 5),
                          child: Column(
                            children: [
                              Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: [
                                  Text('Average Day',style: TextStyle(fontSize: 17)),
                                  MaterialButton(

                                    color: Colors.green,
                                    onPressed: (){
                                      Navigator.of(context).push(MaterialPageRoute(builder: (context)=> AvgDayPage()));
                                    },
                                    child: Text('More...'),
                                  )
                                ],
                              ),
                              Divider(),
                              Container(
                                  height: 400,
                                  padding: EdgeInsets.all(10),
                                  child: Padding(
                                      padding: EdgeInsets.all(8),
                                      child: (!days.isEmpty)
                                          ? Column(
                                        children: [

                                          Expanded(
                                              child: SfCircularChart(legend: Legend(isVisible: true,position: LegendPosition.bottom,overflowMode: LegendItemOverflowMode.wrap), series: <CircularSeries>[
                                                // Render pie chart
                                                PieSeries<CatMapData, String>(
                                                    dataSource: avgDayData,
                                                    pointColorMapper: (CatMapData data, _) => data.color,
                                                    xValueMapper: (CatMapData data, _) => data.name,
                                                    yValueMapper: (CatMapData data, _) => data.time,
                                                    dataLabelMapper: (CatMapData sales, _) => MinutesToTimeString(sales.time),
                                                    dataLabelSettings: DataLabelSettings(isVisible: true, useSeriesColor: true, overflowMode: OverflowMode.shift, showZeroValue: false))
                                              ]))
                                        ],
                                      )
                                          : Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()]))),

                            ],
                          ),
                        )
                      ),
                      Card(
                        child: Container(
                          padding: EdgeInsets.all(8),
                          child: Column(
                            children: [
                              Row(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: [
                                  Text("Compare",style: TextStyle(fontSize: 17)),
                                ],
                              ),
                              Divider(),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.spaceAround,
                                children: [
                                  MaterialButton(color: Colors.blue,onPressed: (){}, child: Text("Task Types"),),
                                  MaterialButton(color: Colors.blue,onPressed: (){}, child: Text("Categories"),),
                                  MaterialButton(color: Colors.blue,onPressed: (){}, child: Text("Days"),),
                                ],
                              )
                            ],
                          ),
                        ),
                      )
                    ],
                  )
                ),
              ),
            ),
          ),
        ],
      )
    );
  }
}

class AnalyticTools{

  static Map<DateTime, double> getProductivities(DateTimeRange _range){
    DateTimeRange range = DateTimeRange(start: DateTime(_range.start.year, _range.start.month,_range.start.day, 0,0,0), end: DateTime(_range.end.year, _range.end.month,_range.end.day, 23,59,59));
    Map<DateTime, double> prodData = <DateTime, double>{};
    Map<DateTime, int> prodActs = <DateTime, int>{};
    Debug.Log("Calculating productivity between ${range.start} - ${range.end}");
    //PASS 1: Split Activities into prod and unprod
    for (var activity in User.activities) {
      if(activity.startTime.isAfter(range.start) && activity.endTime.isBefore(range.end)){
        //Eligible for anal
        DateTime day = DateTime(activity.startTime.year, activity.startTime.month, activity.startTime.day);
        if(activity.taskType!.cat!.productive){
          if(prodActs.containsKey(day)){
            int _prod = prodActs[day] ?? 0;
            prodActs.update(day, (value) =>  _prod +activity.endTime.difference(activity.startTime).inMinutes);
          }else{
            prodActs.putIfAbsent(day, () => activity.endTime.difference(activity.startTime).inMinutes);
          }
        }
      }
    }

    //PASS 2: Calculate productivity percentage and add them into a list
    for(int i = 0; i <= range.end.difference(range.start).inDays; i++){
      DateTime day = DateTime(range.start.add(Duration(days: i)).year,range.start.add(Duration(days: i)).month,range.start.add(Duration(days: i)).day);

        double productivity = ((prodActs[day] ?? 0) / 1440) * 100;
        Debug.LogTest('productivity @ $day = $productivity');
        prodData.putIfAbsent(day, () => productivity);

    }

    return prodData;
  }

  static double dailyThreshold = 0.9;
  static int activityGroupingThreshold = 5;

  static List<Activity> getAverageDayActs(DateTimeRange range){
    int totalDays = range.end.difference(range.start).inDays;

    Map<TaskType, List<AvgActData>> avgActs = <TaskType, List<AvgActData>>{};
    Map<TaskType, List<DateTimeRange>> acts = <TaskType, List<DateTimeRange>>{};
    List<Activity> listToReturn = [];
    //PASS 1: Split Activities and mark their time range
    User.activities.forEach((element) {
      if(element.startTime.isAfter(range.start) && element.endTime.isBefore(range.end)){
        //Eligible activity to calculate
        if(acts.containsKey(element.taskType)){
          acts[element.taskType]!.add(DateTimeRange(start: element.startTime, end: element.endTime));
        }else{
          acts.putIfAbsent(element.taskType, () => [DateTimeRange(start: element.startTime, end: element.endTime)]);
        }
      }
    });
    Debug.Log('Analysing ${acts.length} activities');
    //PASS 2: Calculate avg Time Range for each Activity
    acts.forEach((key, value) {
      if(value.length < totalDays * dailyThreshold){
        //Not a frequent Activity,
      }else{
        //Iterate through the time ranges of this activity
        for (var _actTime in value) {
          DateTime _start = DateTime(0,0,0,_actTime.start.hour, _actTime.start.minute);
          DateTime _end = DateTime(0,0,0,_actTime.end.hour, _actTime.end.minute);
          if(_start.isAfter(_end)){Debug.LogError('${key.name} start after end? : $_start, $_end'); continue;}
          DateTimeRange actTime = DateTimeRange(start: _start, end: _end);
          if(!avgActs.containsKey(key)){
            avgActs.putIfAbsent(key, () => []);
          }
          if(avgActs[key]!.isEmpty){
            //No need to check groups. No groups exists.
            avgActs[key]!.add(AvgActData(actTime, 1, 1));
          }else{
            //Check for the closest time group
            bool foundGroup = false;
            for(int i = 0; i < avgActs[key]!.length; i++){
              if(foundGroup){continue;}
              DateTimeRange avgTime = avgActs[key]![i].avgRange;
              int count = avgActs[key]![i].count;
              if(actTime.start.difference(avgTime.start).inHours.abs() < activityGroupingThreshold && actTime.end.difference(avgTime.end).inHours.abs() < activityGroupingThreshold){
                foundGroup = true;
                int curStartMin = (avgTime.start.hour * 60) + avgTime.start.minute;
                int curEndMin = (avgTime.end.hour * 60) + avgTime.end.minute;
                int newStartMin = (actTime.start.hour * 60) + actTime.start.minute;
                int newEndMin = (actTime.end.hour * 60) + actTime.end.minute;

                int avgStartMin = ((curStartMin + newStartMin)/2).toInt();
                int avgEndMin = ((curEndMin + newEndMin)/2).toInt();

                Debug.Log('Avged  : ${key.name} [$i] : ${avgStartMin} - ${avgEndMin}');
                if(avgStartMin > avgEndMin){
                  //Malfunctioned
                  Debug.LogError('Start is after End? Wut???\nAvged  : ${key.name}[$i] : ${avgStartMin} - ${avgEndMin}');
                }else {
                  DateTime baseline = DateTime(0, 0, 0, 0, 0);
                  // avgActs[key]!.keys.toList()[i] =
                  //     DateTimeRange(start: baseline.add(Duration(minutes: avgStartMin)), end: baseline.add(Duration(minutes: avgEndMin)));
                  // avgActs[key]!.values.toList()[i]++;
                  //avgActs[key]!.removeWhere((key, value) => key==avgTime);
                  avgActs[key]![i].avgRange = DateTimeRange(start: baseline.add(Duration(minutes: avgStartMin)), end: baseline.add(Duration(minutes: avgEndMin)));
                  avgActs[key]![i].count++;
                }

                break;
              }
            }

            if(!foundGroup){
              avgActs[key]!.add(AvgActData(actTime, 1, 1));
            }
          }
        }
      }
    });

    //PASS 3: Prepare the Activity list to return

    avgActs.forEach((key, value) {
      value.sort((a,b) => b.count.compareTo(a.count));
      value.forEach((element) {
        Activity thisAct = Activity(key, element.avgRange.start, element.avgRange.end);
        Debug.LogResponse(
            '${thisAct.taskType.name} (${element.count}) -> (${element.dailyCountAvg}) : ${DateFormat('HH:mm').format(thisAct.startTime)} - ${DateFormat('HH:mm').format(
                thisAct.endTime)}');
        if(element.count < totalDays * dailyThreshold/2){
          Debug.Log('Ignoring due to DailyThreshold, ${element.count} < ${totalDays * dailyThreshold/2}');
        }else {

          listToReturn.add(thisAct);
        }
      });
      // value.forEach((act, count) {
      //
      // });
    });

    return listToReturn;
  }
}

class AvgActData{
  AvgActData(this.avgRange, this.count, this.dailyCountAvg);

  DateTimeRange avgRange;
  int count;
  double dailyCountAvg;
}
