import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:marianum_mobile/api/webuntis/queries/getHolidays/getHolidaysResponse.dart';
import 'package:timetable_view/timetable_view.dart';

import '../../../api/webuntis/queries/getHolidays/getHolidays.dart';
import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
import '../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
import '../../../api/webuntis/queries/getTimetable/getTimetableResponse.dart';
import '../../../data/timetable/timetableProps.dart';

extension DateHelpers on DateTime {
  bool isToday() {
    final now = DateTime.now();
    return now.day == this.day &&
        now.month == this.month &&
        now.year == this.year;
  }

  bool isYesterday() {
    final yesterday = DateTime.now().subtract(Duration(days: 1));
    return yesterday.day == this.day &&
        yesterday.month == this.month &&
        yesterday.year == this.year;
  }
}


class WeekView extends StatefulWidget {
  final TimetableProps value;
  const WeekView(this.value, {Key? key}) : super(key: key);

  @override
  State<WeekView> createState() => _WeekViewState();
}

class _WeekViewState extends State<WeekView> {
  @override
  Widget build(BuildContext context) {
    return TimetableView(
      laneEventsList: _buildLaneEvents(widget.value),
      onEventTap: (TableEvent event) {

        try {
          GetTimetableResponseObject timetableData = widget.value.getTimetableResponse.result.firstWhere((element) => element.id == event.eventId);
          GetSubjectsResponseObject subject = widget.value.getSubjectsResponse.result.firstWhere((subject) => subject.id == timetableData.su[0]['id']);
          GetRoomsResponseObject room = widget.value.getRoomsResponse.result.firstWhere((room) => room.id == timetableData.ro[0]['id']);

          showModalBottomSheet(context: context, builder: (context) => Column(
            children: [
              Padding(
                padding: EdgeInsets.symmetric(vertical: 30),
                child: Center(
                  child: Column(
                    children: [
                      const Icon(Icons.info),
                      const SizedBox(height: 10),
                      Text("${subject.alternateName} - (${subject.longName})", style: const TextStyle(fontSize: 30)),
                      Text("${Jiffy(event.startTime).format("HH:mm")} - ${Jiffy(event.endTime).format("HH:mm")}", style: const TextStyle(fontSize: 15)),
                    ],
                  ),
                ),
              ),

              Expanded(
                child: ListView(
                  children: [
                    ListTile(
                      leading: const Icon(Icons.notifications_active),
                      title: Text("Status: ${timetableData.code != null ? "Entfällt" : "Findet statt"}"),
                    ),
                    ListTile(
                      leading: const Icon(Icons.room),
                      title: Text("Raum: ${room.name}"),
                      trailing: const Icon(Icons.house_outlined),
                    ),
                    ListTile(
                      leading: const Icon(Icons.person),
                      title: Text("Lehrkraft: (${timetableData.te[0]['name']}) ${timetableData.te[0]['longname']}"),
                      trailing: const Icon(Icons.textsms_outlined),
                    ),
                    ListTile(
                      leading: const Icon(Icons.abc),
                      title: Text("Typ: ${timetableData.activityType}"),
                    ),
                    ListTile(
                      leading: const Icon(Icons.people),
                      title: Text("Klasse(n): ${timetableData.kl.map((e) => e['name']).join(", ")}"),
                    )
                  ],
                ),
              )
            ],
          ));


        } on StateError {
          return;
        }
      },
      timetableStyle: CustomTableStyle(context),
      onEmptySlotTap: (int laneIndex, TableEventTime start, TableEventTime end) => {

      },
    );
  }

  List<LaneEvents> _buildLaneEvents(TimetableProps data) {
    List<LaneEvents> laneEvents = List<LaneEvents>.empty(growable: true);
    Jiffy.locale("de"); // todo move outwards

    GetTimetableResponse timetable = data.getTimetableResponse;
    GetRoomsResponse rooms = data.getRoomsResponse;
    GetSubjectsResponse subjects = data.getSubjectsResponse;
    GetHolidaysResponse holidays = data.getHolidaysResponse;

    List<int> dayList = timetable.result.map((e) => e.date).toSet().toList();
    dayList.sort((a, b) => a-b);

    for(int i = 0; i <= data.endDate.difference(data.startDate).inDays; i++) {
      DateTime currentDay = data.startDate.copyWith().add(Duration(days: i));

      // Check Holiday Information
      GetHolidaysResponseObject? holidayInfo = GetHolidays.find(holidays, time: currentDay);
      if(holidayInfo != null) {
        laneEvents.add(
            LaneEvents(
              lane: getLane(currentDay),
              events: List<TableEvent>.of([
                TableEvent(
                  title: holidayInfo.name,
                  eventId: holidayInfo.id,
                  laneIndex: data.startDate.millisecondsSinceEpoch,
                  startTime: parseTime(0800),
                  endTime: parseTime(1500),
                  padding: const EdgeInsets.all(5),
                  backgroundColor: const Color(0xff3D62B3),
                  location: "\n${holidayInfo.longName}",
                )
              ]),
            )
        );
      }
    }

    for (var day in dayList) {
      DateTime currentDay = DateTime.parse("$day");
      Lane currentLane = getLane(currentDay);
      //Every Day

      List<TableEvent> events = List<TableEvent>.generate(
          timetable.result.where((element) => element.date == day).length, (index) {
            GetTimetableResponseObject tableEvent = timetable.result.where((element) => element.date == day).elementAt(index);
            GetSubjectsResponseObject subject = subjects.result.firstWhere((subject) => subject.id == tableEvent.su[0]['id']);

            return TableEvent(
              title: "${getEventPrefix(tableEvent.code)}${subject.alternateName} (${subject.longName})",
              eventId: tableEvent.id,
              laneIndex: day,
              startTime: parseTime(tableEvent.startTime),
              endTime: parseTime(tableEvent.endTime),
              padding: const EdgeInsets.all(5),
              backgroundColor: getEventColor(
                tableEvent.code ?? "",
                currentDay.add(Duration(hours: parseTime(tableEvent.startTime).hour, minutes: parseTime(tableEvent.startTime).minute)),
                currentDay.add(Duration(hours: parseTime(tableEvent.endTime).hour, minutes: parseTime(tableEvent.endTime).minute)),
              ),
              location: "\n${rooms.result.firstWhere((room) => room.id == tableEvent.ro[0]['id']).name} - ${tableEvent.te[0]['longname']} (${tableEvent.te[0]['name']})",
            );
          }
      );

      //Timepointer
      if(currentDay.isToday()) {
        events.add(TableEvent(
          title: "",
          eventId: 0,
          laneIndex: day,
          startTime: formatTime(DateTime.now()),
          endTime: formatTime(DateTime.now().add(const Duration(minutes: 3))),
          backgroundColor: Theme.of(context).disabledColor,
        ));
      }

      laneEvents.add(
        LaneEvents(
          lane: currentLane,
          events: events
        )
      );
    }

    return laneEvents;
  }

  Lane getLane(DateTime currentDay) {
    return Lane(
      backgroundColor: currentDay.isToday() ? Theme.of(context).dividerColor : Colors.white,
      laneIndex: currentDay.millisecondsSinceEpoch,
      name: "${Jiffy(currentDay.toString()).format("dd MMM")}\n${Jiffy(currentDay.toString()).format("EE")}",
      textStyle: TextStyle(
          color: Theme.of(context).primaryColor,
          fontWeight: FontWeight.bold,
          fontSize: 14
      )
    );
  }

  TableEventTime parseTime(int input) {
    String time = input.toString().length < 4 ? "0$input" : input.toString();
    return TableEventTime(hour: int.parse(time.substring(0, 2)), minute: int.parse(time.substring(2, 4)));
  }

  TableEventTime formatTime(DateTime input) {
    return TableEventTime(hour: input.hour, minute: input.minute);
  }

  String getEventPrefix(String? code) {
    if(code == "cancelled") return "Entfällt: ";
    if(code == "irregular") return "Änderung: ";
    return code ?? "";
  }

  Color getEventColor(String? code, DateTime startTime, DateTime endTime) {
    if(code == "cancelled") return const Color(0xff8F19B3);
    if(code == "irregular") return const Color(0xff992B99);
    if(endTime.isBefore(DateTime.now())) return Colors.grey;
    if(startTime.isAfter(DateTime.now())) return Theme.of(context).primaryColor;
    return const Color(0xff99563A);
  }
}

class CustomTableStyle extends TimetableStyle {
  dynamic context;
  CustomTableStyle(this.context);

  @override
  int get startHour => 07;
  @override
  int get endHour => 17;
  @override
  Color get cornerColor => Theme.of(context).primaryColor;
  @override
  Color get timeItemTextColor => Theme.of(context).primaryColor;
  @override
  double get timeItemHeight => MediaQuery.of(context).size.width > 1000 ? 60 : 90;
  @override
  double get timeItemWidth => 50;
  @override
  double get laneHeight => 40;
  @override
  double get laneWidth => (MediaQuery.of(context).size.width - timeItemWidth) / 5;

}