import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/models/Appointments/DoctorListResponse.dart';
import 'package:diplomaticquarterapp/models/Appointments/FreeSlot.dart';
import 'package:diplomaticquarterapp/models/Appointments/timeSlot.dart';
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
import 'package:diplomaticquarterapp/theme/colors.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils_new.dart';
import 'package:diplomaticquarterapp/widgets/buttons/custom_text_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';

import '../../../uitl/date_uitl.dart';

class DocAvailableAppointments extends StatefulWidget {
  DoctorList doctor;
  static bool areSlotsAvailable = false;
  static bool areAppointmentsAvailable = false;
  static DateTime selectedAppoDateTime;
  static String selectedDate;
  static String selectedTime;
  bool isLiveCareAppointment;
  final dynamic doctorSchedule;
  static int initialSlotDuration;

  DocAvailableAppointments({@required this.doctor, this.doctorSchedule, @required this.isLiveCareAppointment});

  @override
  _DocAvailableAppointmentsState createState() => _DocAvailableAppointmentsState();
}

class _DocAvailableAppointmentsState extends State<DocAvailableAppointments> with TickerProviderStateMixin {
  Map<DateTime, List> _events;
  AnimationController _animationController;
  CalendarController _calendarController;

  AppSharedPreferences sharedPref = new AppSharedPreferences();

  var selectedDate = "";
  dynamic selectedDateJSON;
  dynamic jsonFreeSlots;

  List<TimeSlot> docFreeSlots = [];
  List<TimeSlot> dayEvents = [];

  int selectedButtonIndex = 0;

  dynamic freeSlotsResponse;

  ScrollController _scrollController;

  var language;
  bool isLiveCareSchedule;

  @override
  void didUpdateWidget(covariant DocAvailableAppointments oldWidget) {
    if (oldWidget.doctorSchedule != widget.doctorSchedule) {
      _onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date']));
      _calendarController.selectedDate = DateUtil.convertStringToDate(widget.doctorSchedule['Date']);
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    final _selectedDay = DateTime.now();

    _scrollController = new ScrollController();

    _events = {
      _selectedDay: ['Event A0']
    };

    WidgetsBinding.instance.addPostFrameCallback((_) async {
      getCurrentLanguage();
      isLiveCareSchedule = await this.sharedPref.getBool(IS_LIVECARE_APPOINTMENT);
      if (isLiveCareSchedule != null && isLiveCareSchedule)
        getDoctorScheduledFreeSlots(context, widget.doctor);
      else {
        getDoctorFreeSlots(context, widget.doctor);
      }
    });

    _calendarController = CalendarController();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 50),
    );

    _animationController.forward();
  }

  @override
  void dispose() {
    _animationController.dispose();
    _calendarController.dispose();
    super.dispose();
  }

  void _onDaySelected(DateTime day) {
    final DateFormat formatter = DateFormat('yyyy-MM-dd');
    setState(() {
      this.selectedDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day, language);
      openTimeSlotsPickerForDate(day, docFreeSlots);
      DocAvailableAppointments.selectedDate = formatter.format(day);
      _calendarController.selectedDate = day;
      print(_calendarController.selectedDate);
    });
  }

  ProjectViewModel projectViewModel;

  @override
  Widget build(BuildContext context) {
    projectViewModel = Provider.of(context);
    return SingleChildScrollView(
      child: Container(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            _buildTableCalendarWithBuilders(),
            Padding(
              padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
              child: Text(selectedDate, style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600, letterSpacing: -0.64)),
            ),
            DocAvailableAppointments.areSlotsAvailable
                ? Container(
                    height: 40,
                    child: ListView.builder(
                      controller: _scrollController,
                      scrollDirection: Axis.horizontal,
                      itemCount: dayEvents.length,
                      itemBuilder: (context, index) {
                        return Container(
                          margin: EdgeInsets.only(right: (index == dayEvents.length - 1) ? 16 : 5.0, left: index == 0 ? 16 : 5),
                          child: index == selectedButtonIndex ? getSelectedButton(index) : getNormalButton(index),
                        );
                      },
                    ),
                  )
                : Center(
                    child: Padding(
                    padding: const EdgeInsets.only(left: 12.0, right: 12.0),
                    child: Text(TranslationBase.of(context).noSlotsError, style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: CustomColors.grey)),
                  )),
          ],
        ),
      ),
    );
  }

  Widget _buildTableCalendarWithBuilders() {
    return Container(
        decoration: cardRadius(12),
        margin: EdgeInsets.all(16),
        clipBehavior: Clip.antiAlias,
        child: Padding(
          padding: const EdgeInsets.only(bottom: 12),
          child: Container(
            child: SfCalendar(
              controller: _calendarController,
              minDate: DateTime.now(),
              // showNavigationArrow: true,
              headerStyle: CalendarHeaderStyle(textAlign: TextAlign.center, textStyle: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600, letterSpacing: -0.46)),
              viewHeaderStyle: ViewHeaderStyle(dayTextStyle: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: CustomColors.black)),
              view: CalendarView.month,
              todayHighlightColor: Colors.transparent,
              todayTextStyle: TextStyle(color: Colors.black),
              selectionDecoration: containerColorRadiusBorderWidthCircular(Colors.transparent, 4, CustomColors.green, 2.5),
              cellBorderColor: Colors.white,
              dataSource: MeetingDataSource(_getDataSource()),
              monthViewSettings: const MonthViewSettings(appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, showTrailingAndLeadingDates: false, appointmentDisplayCount: 1),
              onTap: (CalendarTapDetails details) {
                _calendarController.selectedDate = details.date;
                _onDaySelected(details.date);
              },
            ),
          ),
        ));
  }

  List<Meeting> _getDataSource() {
    final List<Meeting> meetings = <Meeting>[];

    _events.forEach((key, value) {
      final DateTime startTime = DateTime(key.year, key.month, key.day, 9, 0, 0);
      final DateTime endTime = startTime.add(const Duration(hours: 2));
      meetings.add(Meeting("", startTime, endTime, CustomColors.green, false));
    });
    return meetings;
  }

  openTimeSlotsPickerForDate(DateTime dateStart, List<TimeSlot> freeSlots) {
    dayEvents.clear();
    DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0);

    freeSlots.forEach((v) {
      if (v.start == dateStartObj) dayEvents.add(v);
    });

    setState(() {
      if (dayEvents.length != 0) {
        DocAvailableAppointments.areSlotsAvailable = true;
        selectedButtonIndex = 0;
        DocAvailableAppointments.selectedTime = dayEvents[selectedButtonIndex].isoTime;
      } else
        DocAvailableAppointments.areSlotsAvailable = false;
    });
  }

  Future<Map<DateTime, List>> _getJSONSlots() async {
    Map<DateTime, List> _eventsParsed;
    List<FreeSlot> slotsList = [];
    DateTime date;
    final DateFormat formatter = DateFormat('HH:mm');
    final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
    for (var i = 0; i < freeSlotsResponse.length; i++) {
      date = (isLiveCareSchedule != null && isLiveCareSchedule)
          ? DateUtil.convertStringToDate(freeSlotsResponse[i])
          : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[i], widget.doctor.projectID);
      slotsList.add(FreeSlot(date, ['slot']));
      docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date));
    }
    _eventsParsed = Map.fromIterable(slotsList, key: (e) => e.slot, value: (e) => e.event);
    setState(() {
      DocAvailableAppointments.selectedDate = dateFormatter.format((isLiveCareSchedule != null && isLiveCareSchedule)
          ? DateUtil.convertStringToDate(freeSlotsResponse[0])
          : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID));
      DocAvailableAppointments.selectedAppoDateTime = (isLiveCareSchedule != null && isLiveCareSchedule)
          ? DateUtil.convertStringToDate(freeSlotsResponse[0])
          : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID);
      selectedDate = DateUtil.getWeekDayMonthDayYearDateFormatted(
          (isLiveCareSchedule != null && isLiveCareSchedule)
              ? DateUtil.convertStringToDate(freeSlotsResponse[0])
              : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID),
          language);
      selectedDateJSON = freeSlotsResponse[0];
    });
    openTimeSlotsPickerForDate(
        (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(selectedDateJSON) : DateUtil.convertStringToDateSaudiTimezone(selectedDateJSON, widget.doctor.projectID),
        docFreeSlots);
    _calendarController.selectedDate =
        (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(selectedDateJSON) : DateUtil.convertStringToDateSaudiTimezone(selectedDateJSON, widget.doctor.projectID);
    _calendarController.displayDate = _calendarController.selectedDate;
    return _eventsParsed;
  }

  Widget getNormalButton(int index) {
    return CustomTextButton(
      backgroundColor: Colors.white,
      elevation: 0,
      side: BorderSide(
          color: Colors.black, //Color of the border
          style: BorderStyle.solid, //Style of the border
          width: 1.5 //width of the border
          ),
      onPressed: () {
        final timeslot = dayEvents[index];
        DocAvailableAppointments.selectedAppoDateTime = timeslot.end;

        setState(() {
          selectedButtonIndex = index;
          DocAvailableAppointments.selectedTime = dayEvents[index].isoTime;
          print(DocAvailableAppointments.selectedTime);
        });
        projectViewModel.analytics.appointment.book_appointment_time_selection(appointment_type: 'regular', dateTime: timeslot.end, doctor: widget.doctor);
      },
      child: Text(dayEvents[index].isoTime, style: TextStyle(fontSize: 12.0, color: Color(0xFF60686b))),
    );
  }

  Widget getSelectedButton(int index) {
    return CustomTextButton(
      backgroundColor: CustomColors.green,
      elevation: 0,
      side: BorderSide(
          color: CustomColors.green, //Color of the border
          style: BorderStyle.solid, //Style of the border
          width: 1.5 //width of the border
          ),
      onPressed: () {
        setState(() {
          selectedButtonIndex = index;
          DocAvailableAppointments.selectedTime = dayEvents[index].isoTime;
          print(DocAvailableAppointments.selectedTime);
        });
      },
      child: Text(dayEvents[index].isoTime, style: TextStyle(fontSize: 12.0, color: Colors.white)),
    );
  }

  getDoctorFreeSlots(context, DoctorList docObject) {
    print(DocAvailableAppointments.initialSlotDuration);
    GifLoaderDialogUtils.showMyDialog(context);
    DoctorsListService service = new DoctorsListService();
    service.getDoctorFreeSlots(docObject.doctorID, docObject.clinicID, docObject.projectID, context, projectViewModel).then((res) {
      GifLoaderDialogUtils.hideDialog(context);
      if (res['MessageStatus'] == 1) {
        if (res['FreeTimeSlots'].length != 0) {
          DocAvailableAppointments.initialSlotDuration = res['InitialSlotDuration'];
          DocAvailableAppointments.areAppointmentsAvailable = true;
          freeSlotsResponse = res['FreeTimeSlots'];
          _getJSONSlots().then((value) {
            setState(() => {
                  _events.clear(),
                  _events = value,
                  if (widget.doctorSchedule != null)
                    {_onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date'])), _calendarController.selectedDate = DateUtil.convertStringToDate(widget.doctorSchedule['Date'])}
                });
          });
        } else {
          DocAvailableAppointments.areAppointmentsAvailable = false;
          DocAvailableAppointments.areSlotsAvailable = false;
          AppToast.showErrorToast(message: res['ErrorEndUserMessage']);
        }
      } else {
        AppToast.showErrorToast(message: res['ErrorEndUserMessage']);
      }
    }).catchError((err) {
      GifLoaderDialogUtils.hideDialog(context);
      AppToast.showErrorToast(message: err);
      print(err);
    });
  }

  getDoctorScheduledFreeSlots(context, DoctorList docObject) {
    GifLoaderDialogUtils.showMyDialog(context);
    DoctorsListService service = new DoctorsListService();
    service.getDoctorScheduledFreeSlots(docObject.doctorID, docObject.clinicID, docObject.projectID, docObject.serviceID, context).then((res) {
      GifLoaderDialogUtils.hideDialog(context);
      if (res['MessageStatus'] == 1) {
        if (res['PatientER_DoctorFreeSlots'].length != 0) {
          DocAvailableAppointments.areAppointmentsAvailable = true;
          freeSlotsResponse = res['PatientER_DoctorFreeSlots'];
          _getJSONSlots().then((value) => {
                setState(() => {_events.clear(), _events = value})
              });
        } else {
          DocAvailableAppointments.areAppointmentsAvailable = false;
        }
      } else {
        AppToast.showErrorToast(message: res['ErrorEndUserMessage']);
      }
    }).catchError((err) {
      GifLoaderDialogUtils.hideDialog(context);
      AppToast.showErrorToast(message: err);
      print(err);
    });
  }

  getCurrentLanguage() async {
    var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar');
    setState(() {
      this.language = languageID;
    });
  }
}

class MeetingDataSource extends CalendarDataSource {
  MeetingDataSource(List<Meeting> source) {
    appointments = source;
  }

  @override
  DateTime getStartTime(int index) {
    return _getMeetingData(index).from;
  }

  @override
  DateTime getEndTime(int index) {
    return _getMeetingData(index).to;
  }

  @override
  String getSubject(int index) {
    return _getMeetingData(index).eventName;
  }

  @override
  Color getColor(int index) {
    return _getMeetingData(index).background;
  }

  @override
  bool isAllDay(int index) {
    return _getMeetingData(index).isAllDay;
  }

  Meeting _getMeetingData(int index) {
    final dynamic meeting = appointments[index];
    Meeting meetingData;
    if (meeting is Meeting) {
      meetingData = meeting;
    }
    return meetingData;
  }
}

class Meeting {
  Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay);

  String eventName;
  DateTime from;
  DateTime to;
  Color background;
  bool isAllDay;
}
