import 'package:intl/intl.dart';

import '../../api/apiResponse.dart';
import '../../api/mhsl/customTimetableEvent/get/getCustomTimetableEventCache.dart';
import '../../api/mhsl/customTimetableEvent/get/getCustomTimetableEventParams.dart';
import '../../api/mhsl/customTimetableEvent/get/getCustomTimetableEventResponse.dart';
import '../../api/webuntis/queries/getHolidays/getHolidaysCache.dart';
import '../../api/webuntis/queries/getHolidays/getHolidaysResponse.dart';
import '../../api/webuntis/queries/getRooms/getRoomsCache.dart';
import '../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
import '../../api/webuntis/queries/getSubjects/getSubjectsCache.dart';
import '../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
import '../../api/webuntis/queries/getTimetable/getTimetableCache.dart';
import '../../api/webuntis/queries/getTimetable/getTimetableResponse.dart';
import '../../api/webuntis/webuntisError.dart';
import '../accountData.dart';
import '../dataHolder.dart';

class TimetableProps extends DataHolder {
  final _queryWeek = DateTime.now().add(const Duration(days: 2));

  late DateTime startDate = getDate(_queryWeek.subtract(Duration(days: _queryWeek.weekday - 1)));
  late DateTime endDate = getDate(_queryWeek.add(Duration(days: DateTime.daysPerWeek - _queryWeek.weekday - 2)));

  GetTimetableResponse? _getTimetableResponse;
  GetTimetableResponse get getTimetableResponse => _getTimetableResponse!;

  GetRoomsResponse? _getRoomsResponse;
  GetRoomsResponse get getRoomsResponse => _getRoomsResponse!;

  GetSubjectsResponse? _getSubjectsResponse;
  GetSubjectsResponse get getSubjectsResponse => _getSubjectsResponse!;

  GetHolidaysResponse? _getHolidaysResponse;
  GetHolidaysResponse get getHolidaysResponse => _getHolidaysResponse!;

  GetCustomTimetableEventResponse? _getCustomTimetableEventResponse;
  GetCustomTimetableEventResponse get getCustomTimetableEventResponse => _getCustomTimetableEventResponse!;

  WebuntisError? error;
  WebuntisError? get getError => error;
  bool get hasError => error != null;

  @override
  List<ApiResponse?> properties() => [_getTimetableResponse, _getRoomsResponse, _getSubjectsResponse, _getHolidaysResponse, _getCustomTimetableEventResponse];

  @override
  void run({renew}) {
    GetTimetableCache(
      startdate: int.parse(DateFormat('yyyyMMdd').format(startDate)),
      enddate: int.parse(DateFormat('yyyyMMdd').format(endDate)),
      onUpdate: (GetTimetableResponse data) => {
        _getTimetableResponse = data,
        notifyListeners(),
      },
      onError: (Exception e) => {
        error = e as WebuntisError?,
        notifyListeners(),
      }
    );

    GetRoomsCache(
        onUpdate: (GetRoomsResponse data) => {
          _getRoomsResponse = data,
          notifyListeners(),
        }
    );

    GetSubjectsCache(
        onUpdate: (GetSubjectsResponse data) => {
          _getSubjectsResponse = data,
          notifyListeners(),
        }
    );

    GetHolidaysCache( // This broke in the past. Below here is backup simulation for an empty holiday block
      onUpdate: (GetHolidaysResponse data) => {
        _getHolidaysResponse = data,
        notifyListeners(),
      }
    );
    // _getHolidaysResponse = GetHolidaysResponse.fromJson(jsonDecode("""
    //   {"jsonrpc":"2.0","id":"ID","result":[]}
    // """));

    GetCustomTimetableEventCache(
      renew: renew,
      GetCustomTimetableEventParams(
        AccountData().getUserSecret()
      ),
      onUpdate: (GetCustomTimetableEventResponse data) => {
        _getCustomTimetableEventResponse = data,
        notifyListeners(),
      }
    );

    notifyListeners();
  }

  DateTime getDate(DateTime d) => DateTime(d.year, d.month, d.day);

  bool isWeekend(DateTime queryDate) => queryDate.weekday == DateTime.saturday || queryDate.weekday == DateTime.sunday;

  void updateWeek(DateTime start, DateTime end) {
    properties().forEach((element) => element = null);
    error = null;
    notifyListeners();
    startDate = start;
    endDate = end;
    try {
      run();
    } on WebuntisError catch(e) {
      error = e;
      notifyListeners();
    }
  }

  void resetWeek()  {
    error = null;
    notifyListeners();

    var queryWeek = DateTime.now().add(const Duration(days: 2));

    startDate = getDate(queryWeek.subtract(Duration(days: queryWeek.weekday - 1)));
    endDate = getDate(queryWeek.add(Duration(days: DateTime.daysPerWeek - queryWeek.weekday)));

    run();
    notifyListeners();
  }
}