import 'package:kreta_api/kreta_api.dart';
import 'package:firka/core/average_helper.dart';
import 'package:firka/ui/components/firka_card.dart';
import 'package:firka/ui/components/grade_helpers.dart';
import 'package:firka/ui/phone/widgets/grade_chart.dart';
import 'package:firka/ui/phone/widgets/grade_summary_bar.dart';
import 'package:firka/ui/shared/grade_small_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

import 'package:firka/api/consts.dart';
import 'package:firka/core/debug_helper.dart';
import 'package:firka/core/state/firka_state.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/core/bloc/home_refresh_cubit.dart';
import 'package:firka/core/settings.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/shared/delayed_spinner.dart';

class HomeGradesScreen extends StatefulWidget {
  final AppInitialization data;

  const HomeGradesScreen(this.data, {super.key});

  @override
  State<StatefulWidget> createState() => _HomeGradesScreen();
}

String activeSubjectUid = "";
String subjectName = "";
String subjectId = "";
String subjectCategory = "";
List<Subject> subjectInfo = [];

class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
  ApiResponse<List<Grade>>? grades;
  ApiResponse<List<Lesson>>? week;
  ApiResponse<List<ClassGroup>>? classGroups;
  ApiResponse<List<SubjectAverage>>? lessons;

  void _onRefreshRequested(BuildContext context) async {
    final cubit = context.read<HomeRefreshCubit>();
    var now = timeNow();
    var start = now.subtract(Duration(days: now.weekday - 1));
    var end = start.add(Duration(days: 6));

    grades = await widget.data.client.getGrades(forceCache: false);
    week = await widget.data.client.getTimeTable(start, end, forceCache: false);
    classGroups = await widget.data.client.getClassGroups(forceCache: false);
    if (classGroups?.response?.isNotEmpty ?? false) {
      var group = classGroups!.response!.first;
      lessons = await widget.data.client.getSubjectAverage(
        group,
        forceCache: false,
      );
      await Future.delayed(Duration(milliseconds: 100));
    }
    if (mounted) {
      setState(() {});
      cubit.onRefreshComplete();
    }
  }

  @override
  void initState() {
    super.initState();

    (() async {
      var now = timeNow();
      var start = now.subtract(Duration(days: now.weekday - 1));
      var end = start.add(Duration(days: 6));

      grades = await widget.data.client.getGrades();
      week = await widget.data.client.getTimeTable(start, end);
      classGroups = await widget.data.client.getClassGroups();
      if (classGroups?.response?.isNotEmpty ?? false) {
        var group = classGroups!.response!.first;
        lessons = await widget.data.client.getSubjectAverage(group);
        await Future.delayed(Duration(milliseconds: 100));
      }
      if (mounted) setState(() {});
    })();
  }

  @override
  Widget build(BuildContext context) {
    return BlocListener<HomeRefreshCubit, HomeRefreshState>(
      listenWhen: (previous, current) =>
          current.refreshTrigger != previous.refreshTrigger,
      listener: (context, state) {
        _onRefreshRequested(context);
      },
      child: _buildContent(context),
    );
  }

  Widget _buildContent(BuildContext context) {
    if (grades == null || week == null) {
      return SizedBox(
        height: MediaQuery.of(context).size.height / 1.35,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [SizedBox(), DelayedSpinnerWidget(), SizedBox()],
        ),
      );
    } else {
      var subjectAvg = 0.00;
      var subjectCount = 0;
      var subjectAvgRounded = 0.00;
      final allGrades = grades!.response!;
      final bySubject = <String, List<Grade>>{};
      for (final g in allGrades) {
        bySubject.putIfAbsent(g.subject.uid, () => []).add(g);
      }
      final gradesForCalculation = <Grade>[];
      for (final subjectGrades in bySubject.values) {
        final feleviOrEvvegi = subjectGrades.where((g) {
          final typeName = g.type.name?.toLowerCase() ?? '';
          return typeName == 'felevi_jegy_ertekeles' ||
              typeName == 'evvegi_jegy_ertekeles';
        }).toList();
        final hasOtherType = subjectGrades.any((g) {
          final typeName = g.type.name?.toLowerCase() ?? '';
          return typeName != 'felevi_jegy_ertekeles' &&
              typeName != 'evvegi_jegy_ertekeles';
        });
        if (!hasOtherType && feleviOrEvvegi.isNotEmpty) {
          final withValue = feleviOrEvvegi
              .where((g) => g.numericValue != null && g.numericValue! > 0)
              .toList();
          if (withValue.isNotEmpty) {
            withValue.sort((a, b) => a.recordDate.compareTo(b.recordDate));
            gradesForCalculation.add(withValue.last);
          }
        } else {
          gradesForCalculation.addAll(
            subjectGrades.where((g) => !shouldIgnoreInAverage(g)),
          );
        }
      }

      final summaryAvg2 = calculateAverage(
        gradesForCalculation,
        applyIgnoreFilter: false,
      );
      final List<Subject> subjects = List<Subject>.empty(growable: true);
      final List<Widget> gradeCards = [];

      for (var grade in allGrades) {
        if (subjects.where((s) => s.uid == grade.subject.uid).isEmpty) {
          subjects.add(grade.subject);
        }
      }

      if (lessons != null && lessons!.response != null) {
        for (var lesson in lessons!.response!) {
          if (subjects.where((s) => s.uid == lesson.uid).isEmpty) {
            subjects.add(
              Subject(
                uid: lesson.uid,
                name: lesson.name,
                category: NameUidDesc(
                  uid: lesson.subjectCategoryId,
                  name: lesson.subjectCategoryName,
                  description: lesson.subjectCategoryDescription,
                ),
                sortIndex: lesson.sortIndex,
              ),
            );
          }
        }
      }

      subjects.sort((s1, s2) => s1.name.compareTo(s2.name));

      for (var subject in subjects) {
        final subjectGrades = allGrades
            .where((g) => g.subject.uid == subject.uid)
            .toList();

        double avg = double.nan;
        if (subjectGrades.isNotEmpty) {
          final feleviOrEvvegi = subjectGrades.where((g) {
            final typeName = g.type.name?.toLowerCase() ?? '';
            return typeName == 'felevi_jegy_ertekeles' ||
                typeName == 'evvegi_jegy_ertekeles';
          }).toList();
          final hasOtherType = subjectGrades.any((g) {
            final typeName = g.type.name?.toLowerCase() ?? '';
            return typeName != 'felevi_jegy_ertekeles' &&
                typeName != 'evvegi_jegy_ertekeles';
          });
          if (!hasOtherType && feleviOrEvvegi.isNotEmpty) {
            final withValue = feleviOrEvvegi
                .where((g) => g.numericValue != null && g.numericValue! > 0)
                .toList();
            if (withValue.isNotEmpty) {
              withValue.sort((a, b) => a.recordDate.compareTo(b.recordDate));
              avg = withValue.last.numericValue!.toDouble();
            }
          } else {
            avg = subjectGrades.getAverageBySubject(subject);
          }
        }

        if (avg.isNaN) {
          gradeCards.add(
            GestureDetector(
              child: GradeSmallCard(allGrades, subject),
              onTap: () {
                activeSubjectUid = subject.uid;
                subjectName = subject.name;
                subjectId = subject.uid;
                subjectCategory = subject.category.name!;
                subjectInfo = subjects
                    .where((s) => s.uid == subject.uid)
                    .toList();
                context.go('/grades/subject/${subject.uid}');
              },
            ),
          );
        } else {
          gradeCards.add(
            GestureDetector(
              child: GradeSmallCard(allGrades, subject),
              onTap: () {
                activeSubjectUid = subject.uid;
                subjectName = subject.name;
                subjectId = subject.uid;
                subjectCategory = subject.category.name!;
                subjectInfo = subjects
                    .where((s) => s.uid == subject.uid)
                    .toList();
                context.go('/grades/subject/${subject.uid}');
              },
            ),
          );
        }

        if (!avg.isNaN && avg > 0) {
          subjectCount++;
          subjectAvg += avg;
          final rounding = widget.data.settings
              .group("settings")
              .subGroup("application")
              .subGroup("rounding");
          subjectAvgRounded += roundGrade(
            avg,
            t1: rounding.dbl("1"),
            t2: rounding.dbl("2"),
            t3: rounding.dbl("3"),
            t4: rounding.dbl("4"),
          );
        }
      }

      subjectAvg /= subjectCount;
      subjectAvgRounded /= subjectCount;

      if (subjectCount == 0) {
        subjectAvg = 0.00;
        subjectAvgRounded = 0.00;
      }

      final rounding = widget.data.settings
          .group("settings")
          .subGroup("application")
          .subGroup("rounding");
      var subjectAvgColor = getGradeColor(
        subjectAvg,
        t1: rounding.dbl("1"),
        t2: rounding.dbl("2"),
        t3: rounding.dbl("3"),
        t4: rounding.dbl("4"),
      );

      return Padding(
        padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 12.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Text(
                  widget.data.l10n.subjects,
                  style: appStyle.fonts.H_H2.apply(
                    color: appStyle.colors.textPrimary,
                  ),
                ),
              ],
            ),
            GradeChartWithInteraction(grades: gradesForCalculation),
            SizedBox(height: 2),
            GradeSummaryBar(
              grades: gradesForCalculation,
              l10n: widget.data.l10n,
            ),
            SizedBox(height: 12),
            Expanded(
              child: ListView(
                children: [
                  Text(
                    widget.data.l10n.your_subjects,
                    style: appStyle.fonts.H_14px.apply(
                      color: appStyle.colors.textSecondary,
                    ),
                  ),
                  SizedBox(height: 16),
                  ...gradeCards,
                  SizedBox(height: 16),
                  Text(
                    widget.data.l10n.data,
                    style: appStyle.fonts.B_16SB.apply(
                      color: appStyle.colors.textSecondary,
                    ),
                  ),
                  SizedBox(height: 16),
                  FirkaCard(
                    left: [
                      Text(
                        widget.data.l10n.subject_avg,
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                    right: [
                      Card(
                        shadowColor: Colors.transparent,
                        color: subjectAvgColor.withAlpha(38),
                        child: Padding(
                          padding: EdgeInsets.only(
                            left: 8,
                            right: 8,
                            top: 4,
                            bottom: 4,
                          ),
                          child: Text(
                            subjectAvg.toStringAsFixed(2),
                            style: appStyle.fonts.B_16SB.apply(
                              color: subjectAvgColor,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  FirkaCard(
                    left: [
                      Text(
                        widget.data.l10n.subject_avg_rounded,
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                    right: [
                      Card(
                        shadowColor: Colors.transparent,
                        color: subjectAvgColor.withAlpha(38),
                        child: Padding(
                          padding: EdgeInsets.only(
                            left: 8,
                            right: 8,
                            top: 4,
                            bottom: 4,
                          ),
                          child: Text(
                            subjectAvgRounded.toStringAsFixed(2),
                            style: appStyle.fonts.B_16SB.apply(
                              color: subjectAvgColor,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  FirkaCard(
                    left: [
                      Text(
                        widget.data.l10n.overall_avg,
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                    right: [
                      Card(
                        shadowColor: Colors.transparent,
                        color: subjectAvgColor.withAlpha(38),
                        child: Padding(
                          padding: EdgeInsets.only(
                            left: 8,
                            right: 8,
                            top: 4,
                            bottom: 4,
                          ),
                          child: Text(
                            summaryAvg2.toStringAsFixed(2),
                            style: appStyle.fonts.B_16SB.apply(
                              color: subjectAvgColor,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  FirkaCard(
                    left: [
                      Text(
                        widget.data.l10n.class_avg,
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                  ),
                  FirkaCard(
                    left: [
                      Text(
                        widget.data.l10n.class_n,
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                    right: [
                      Text(
                        week!.response!
                            .where(
                              (lesson) =>
                                  lesson.type.name != TimetableConsts.event,
                            )
                            .length
                            .toString(),
                        style: appStyle.fonts.B_16SB.apply(
                          color: appStyle.colors.textPrimary,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    }
  }
}
