import 'package:diameter/components/detail.dart';
import 'package:diameter/components/forms/boolean_form_field.dart';
import 'package:diameter/components/forms/date_time_form_field.dart';
import 'package:diameter/components/forms/time_of_day_form_field.dart';
import 'package:diameter/utils/dialog_utils.dart';
import 'package:diameter/components/forms/auto_complete_dropdown_button.dart';
import 'package:diameter/components/forms/form_wrapper.dart';
import 'package:diameter/models/basal_profile.dart';
import 'package:diameter/models/bolus_profile.dart';
import 'package:diameter/models/log_event.dart';
import 'package:diameter/models/log_event_type.dart';
import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart';
import 'package:diameter/screens/basal/basal_profile_detail.dart';
import 'package:diameter/screens/bolus/bolus_profile_detail.dart';
import 'package:diameter/utils/date_time_utils.dart';
import 'package:flutter/material.dart';

class LogEventDetailScreen extends StatefulWidget {
  static const String routeName = '/log-event';

  final int logEntryId;
  final int endLogEntryId;
  final int id;
  final DateTime? suggestedDate;

  const LogEventDetailScreen(
      {Key? key, this.logEntryId = 0, this.endLogEntryId = 0, this.id = 0, this.suggestedDate})
      : super(key: key);

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

class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
  LogEvent? _logEvent;
  bool _isNew = true;
  bool _isSaving = false;

  List<BolusProfile> _bolusProfiles = [];
  List<BasalProfile> _basalProfiles = [];

  final GlobalKey<FormState> _logEventForm = GlobalKey<FormState>();
  final ScrollController _scrollController = ScrollController();

  late DateTime _time;
  DateTime? _endTime;

  final _timeController = TextEditingController(text: '');
  final _endTimeController = TextEditingController(text: '');

  final _dateController = TextEditingController(text: '');
  final _endDateController = TextEditingController(text: '');

  final _reminderDurationController = TextEditingController(text: '');
  final _notesController = TextEditingController(text: '');

  LogEventType? _eventType;
  final _eventTypeController = TextEditingController(text: '');

  bool _hasEndTime = false;

  BolusProfile? _bolusProfile;
  BasalProfile? _basalProfile;
  final _bolusProfileController = TextEditingController(text: '');
  final _basalProfileController = TextEditingController(text: '');

  List<LogEventType> _logEventTypes = [];

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

    reload();

    _bolusProfiles = BolusProfile.getAll();
    _basalProfiles = BasalProfile.getAll();

    if (widget.id != 0) {
      _reminderDurationController.text =
          (_logEvent!.reminderDuration ?? '').toString();
      _hasEndTime = _logEvent!.hasEndTime;
      _notesController.text = _logEvent!.notes ?? '';

      _eventType = _logEvent!.eventType.target;
      _eventTypeController.text = (_eventType ?? '').toString();

      _basalProfile = _logEvent!.basalProfile.target;
      _basalProfileController.text = (_basalProfile ?? '').toString();

      _bolusProfile = _logEvent!.bolusProfile.target;
      _bolusProfileController.text = (_bolusProfile ?? '').toString();

      _time = _logEvent!.time;
      _endTime = _logEvent!.endTime;
    } else {
      _time = widget.suggestedDate ?? DateTime.now();
    }

    _logEventTypes = LogEventType.getAll();

    updateTime();
    updateEndTime();
  }

  @override
  void dispose() {
    _scrollController.dispose();
    _timeController.dispose();
    _endTimeController.dispose();
    _dateController.dispose();
    _endDateController.dispose();
    _reminderDurationController.dispose();
    _notesController.dispose();
    _eventTypeController.dispose();
    _bolusProfileController.dispose();
    _basalProfileController.dispose();
    super.dispose();
  }

  void reload({String? message}) {
    if (widget.id != 0) {
      setState(() {
        _logEvent = LogEvent.get(widget.id);
      });
    }
    _isNew = _logEvent == null;

    setState(() {
      if (message != null) {
        var snackBar = SnackBar(
          content: Text(message),
          duration: const Duration(seconds: 2),
        );
        ScaffoldMessenger.of(context)
          ..removeCurrentSnackBar()
          ..showSnackBar(snackBar);
      }
    });
  }

  void updateTime() {
    _timeController.text = DateTimeUtils.displayTime(_time);
    _dateController.text = DateTimeUtils.displayDate(_time);
  }

  void updateEndTime() {
    _endTimeController.text = DateTimeUtils.displayTime(_endTime);
    _endDateController.text = DateTimeUtils.displayDate(_endTime);
  }

  void updateBasalProfile(BasalProfile? value) {
    setState(() {
      _basalProfile = value;
      _basalProfileController.text = (_basalProfile ?? '').toString();
    });
  }

  void updateBolusProfile(BolusProfile? value) {
    setState(() {
      _bolusProfile = value;
      _bolusProfileController.text = (_bolusProfile ?? '').toString();
    });
  }

  void onSelectEventType(LogEventType? eventType) {
    setState(() {
      _eventType = eventType;
      _eventTypeController.text = (_eventType ?? '').toString();
    });

    if (eventType != null) {
      setState(() {
        _hasEndTime = eventType.hasEndTime;
        if (eventType.defaultReminderDuration != null) {
          _reminderDurationController.text =
              eventType.defaultReminderDuration.toString();
        }
      });

      if (eventType.basalProfile.target != null) {
        updateBasalProfile(eventType.basalProfile.target);
      }
      if (eventType.bolusProfile.target != null) {
        updateBolusProfile(eventType.bolusProfile.target);
      }
    }
  }

  Future<void> checkIfActiveEventOfTypeExistsBeforeSaving() async {
    if (_eventType != null &&
        LogEvent.eventTypeExistsForTime(_eventType!.id, _time)) {
      await showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              content: const Text(
                  'An Event of this type is already active within the set time frame. What would you like to do?'),
              actions: [
                TextButton(
                  onPressed: () => Navigator.pop(context, 'DISCARD'),
                  child: const Text('DISCARD'),
                ),
                TextButton(
                  onPressed: () => Navigator.pop(context, 'EDIT'),
                  child: const Text('KEEP EDITING'),
                ),
                ElevatedButton(
                  onPressed: () => Navigator.pop(context, 'SAVE'),
                  child: const Text('SAVE'),
                )
              ],
            );
          }).then((value) async {
        if (value == 'DISCARD') {
          Navigator.pop(context);
        } else if (value == 'SAVE') {
          onSave();
        }
      });
    } else {
      onSave();
    }
  }

  void onSave() {
    LogEvent event = LogEvent(
      id: widget.id,
      time: _time,
      endTime: _endTime,
      hasEndTime: _hasEndTime,
      reminderDuration: int.tryParse(_reminderDurationController.text),
      notes: _notesController.text,
    );
    event.eventType.target = _eventType;
    event.basalProfile.target = _basalProfile;
    event.bolusProfile.target = _bolusProfile;
    LogEvent.put(event);
    Navigator.pop(context, ['${_isNew ? 'New' : ''} Event Saved', event]);
  }

  void handleSaveAction() async {
    setState(() {
      _isSaving = true;
    });
    if (_logEventForm.currentState!.validate()) {
      await checkIfActiveEventOfTypeExistsBeforeSaving();
    }
    setState(() {
      _isSaving = false;
    });
  }

  void handleCancelAction() {
    if (Settings.get().showConfirmationDialogOnCancel &&
        ((_isNew &&
                (_notesController.text != '' ||
                    _eventType != null ||
                    _hasEndTime)) ||
            (!_isNew &&
                (_notesController.text != (_logEvent!.notes ?? '') ||
                    _eventType != _logEvent!.eventType.target ||
                    _hasEndTime != _logEvent!.hasEndTime)))) {
      DialogUtils.showCancelConfirmationDialog(
        context: context,
        isNew: _isNew,
        onSave: handleSaveAction,
      );
    } else {
      Navigator.pop(context);
    }
  }

  @override
  Widget build(BuildContext context) {
    final now = DateTime.now();
    return Scaffold(
      appBar: AppBar(
        title: Text(_isNew ? 'New Event' : 'Edit Event'),
      ),
      drawer: const Navigation(currentLocation: LogEventDetailScreen.routeName),
      body: Scrollbar(
        controller: _scrollController,
        child: SingleChildScrollView(
          controller: _scrollController,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              FormWrapper(
                formState: _logEventForm,
                fields: [
                  AutoCompleteDropdownButton<LogEventType>(
                    controller: _eventTypeController,
                    selectedItem: _eventType,
                    label: 'Event Type',
                    items: _logEventTypes,
                    onChanged: onSelectEventType,
                  ),
                  Row(
                    children: [
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.only(right: 5),
                          child: DateTimeFormField(
                            date: _time,
                            label: _hasEndTime ? 'Start Date' : 'Date',
                            controller: _dateController,
                            onChanged: (newTime) {
                              if (newTime != null) {
                                setState(() {
                                  _time = DateTime(newTime.year, newTime.month,
                                      newTime.day, _time.hour, _time.minute);
                                });
                                updateTime();
                              }
                            },
                          ),
                        ),
                      ),
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.only(left: 5),
                          child: TimeOfDayFormField(
                            time: TimeOfDay.fromDateTime(_time),
                            label: _hasEndTime ? 'Start Time' : 'Time',
                            controller: _timeController,
                            onChanged: (newTime) {
                              if (newTime != null) {
                                setState(() {
                                  _time = DateTime(_time.year, _time.month,
                                      _time.day, newTime.hour, newTime.minute);
                                });
                                updateTime();
                              }
                            },
                          ),
                        ),
                      ),
                    ],
                  ),
                  BooleanFormField(
                    value: _hasEndTime,
                    onChanged: (value) {
                      setState(() {
                        _hasEndTime = value;
                      });
                    },
                    label: 'has end time',
                  ),
                  Column(
                      children: _hasEndTime
                          ? [
                              Row(
                                children: [
                                  Expanded(
                                    child: Padding(
                                      padding: const EdgeInsets.only(right: 5),
                                      child: DateTimeFormField(
                                        date: _endTime ?? now,
                                        label: 'End Date',
                                        controller: _endDateController,
                                        onChanged: (newTime) {
                                          if (newTime != null) {
                                            setState(() {
                                              _endTime = DateTime(
                                                  newTime.year,
                                                  newTime.month,
                                                  newTime.day,
                                                  _endTime?.hour ?? 0,
                                                  _endTime?.minute ?? 0);
                                            });
                                            updateEndTime();
                                          }
                                        },
                                      ),
                                    ),
                                  ),
                                  Expanded(
                                    child: Padding(
                                      padding: const EdgeInsets.only(left: 5),
                                      child: TimeOfDayFormField(
                                        time: TimeOfDay.fromDateTime(
                                            _endTime ?? now),
                                        label: 'End Time',
                                        controller: _endTimeController,
                                        onChanged: (newTime) {
                                          if (newTime != null) {
                                            setState(() {
                                              _endTime = DateTime(
                                                  _endTime?.year ?? now.year,
                                                  _endTime?.month ?? now.month,
                                                  _endTime?.day ?? now.day,
                                                  newTime.hour,
                                                  newTime.minute);
                                            });
                                            updateEndTime();
                                          }
                                        },
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                              Padding(
                                padding: const EdgeInsets.symmetric(vertical: 10.0),
                                child: TextFormField(
                                  controller: _reminderDurationController,
                                  keyboardType:
                                      const TextInputType.numberWithOptions(),
                                  decoration: InputDecoration(
                                    labelText: 'Default Reminder Duration',
                                    suffixText: ' min',
                                    enabled: _hasEndTime,
                                  ),
                                ),
                              ),
                              Row(
                                children: [
                                  Expanded(
                                    child: AutoCompleteDropdownButton<
                                        BolusProfile>(
                                      controller: _bolusProfileController,
                                      selectedItem: _bolusProfile,
                                      label: 'Bolus Profile',
                                      items: _bolusProfiles,
                                      onChanged: updateBolusProfile,
                                    ),
                                  ),
                                  IconButton(
                                    onPressed: () {
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) => _bolusProfile ==
                                                  null
                                              ? const BolusProfileDetailScreen()
                                              : BolusProfileDetailScreen(
                                                  id: _basalProfile!.id),
                                        ),
                                      ).then((result) {
                                        updateBolusProfile(result?[1]);
                                        reload(message: result?[0]);
                                      });
                                    },
                                    icon: Icon(_bolusProfile == null
                                        ? Icons.add
                                        : Icons.edit),
                                  ),
                                ],
                              ),
                              Padding(
                                padding: const EdgeInsets.only(top: 10.0),
                                child: Row(
                                  children: [
                                    Expanded(
                                      child: AutoCompleteDropdownButton<
                                          BasalProfile>(
                                        controller: _basalProfileController,
                                        selectedItem: _basalProfile,
                                        label: 'Basal Profile',
                                        items: _basalProfiles,
                                        onChanged: updateBasalProfile,
                                      ),
                                    ),
                                    IconButton(
                                      onPressed: () {
                                        Navigator.push(
                                          context,
                                          MaterialPageRoute(
                                            builder: (context) => _basalProfile ==
                                                    null
                                                ? const BasalProfileDetailScreen()
                                                : BasalProfileDetailScreen(
                                                    id: _basalProfile!.id),
                                          ),
                                        ).then((result) {
                                          updateBasalProfile(result?[1]);
                                          reload(message: result?[0]);
                                        });
                                      },
                                      icon: Icon(_basalProfile == null
                                          ? Icons.add
                                          : Icons.edit),
                                    ),
                                  ],
                                ),
                              )
                            ]
                          : []),
                  TextFormField(
                    controller: _notesController,
                    decoration: const InputDecoration(
                      labelText: 'Notes',
                    ),
                    keyboardType: TextInputType.multiline,
                    minLines: 2,
                    maxLines: 5,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: DetailBottomRow(
        onCancel: handleCancelAction,
        onAction: _isSaving ? null : handleSaveAction,
      ),
    );
  }
}
