import 'package:diameter/components/detail.dart';
import 'package:diameter/components/forms/number_form_field.dart';
import 'package:diameter/components/forms/time_of_day_form_field.dart';
import 'package:diameter/utils/dialog_utils.dart';
import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart';
import 'package:diameter/utils/date_time_utils.dart';
import 'package:diameter/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:diameter/components/forms/form_wrapper.dart';
import 'package:diameter/models/basal.dart';
import 'package:diameter/models/basal_profile.dart';

class BasalDetailScreen extends StatefulWidget {
  static const String routeName = '/basal';

  final int basalProfileId;
  final int id;
  final TimeOfDay? suggestedStartTime;
  final TimeOfDay? suggestedEndTime;

  const BasalDetailScreen(
      {Key? key,
      this.basalProfileId = 0,
      this.id = 0,
      this.suggestedStartTime,
      this.suggestedEndTime})
      : super(key: key);

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

class _BasalDetailScreenState extends State<BasalDetailScreen> {
  Basal? _basal;
  bool _isNew = true;
  bool _isSaving = false;
  bool _isFinalRate = true;

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

  TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0);
  TimeOfDay _endTime = const TimeOfDay(hour: 0, minute: 0);

  final _startTimeController = TextEditingController(text: '');
  final _endTimeController = TextEditingController(text: '');
  final _unitsController =
      TextEditingController(text: 0.toStringAsPrecision(3));

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

    if (widget.suggestedStartTime != null) {
      _startTime = widget.suggestedStartTime!;
    }
    if (widget.suggestedEndTime != null) {
      _endTime = widget.suggestedEndTime!;
    }

    if (_basal != null) {
      _startTime = TimeOfDay.fromDateTime(_basal!.startTime);
      _endTime = TimeOfDay.fromDateTime(_basal!.endTime);
      _unitsController.text = _basal!.units.toStringAsPrecision(3);
    }

    _startTimeController.text = DateTimeUtils.displayTimeOfDay(_startTime);
    _endTimeController.text = DateTimeUtils.displayTimeOfDay(_endTime);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    _startTimeController.dispose();
    _endTimeController.dispose();
    _unitsController.dispose();
    super.dispose();
  }

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

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

  void updateStartTime(TimeOfDay? value) {
    if (value != null) {
      setState(() {
        _startTime = value;
        _startTimeController.text = DateTimeUtils.displayTimeOfDay(_startTime);
      });
    }
  }

  void updateEndTime(TimeOfDay? value) {
    if (value != null) {
      setState(() {
        _endTime = value;
        _endTimeController.text = DateTimeUtils.displayTimeOfDay(_endTime);
        _isFinalRate = widget.suggestedEndTime == null ||
            _endTime == widget.suggestedEndTime!;
      });
    }
  }

  Future<String?> validateTimePeriod() async {
    String? error;
    List<Basal> basalRates = Basal.getAllForProfile(widget.basalProfileId);

    if (basalRates
        .where((other) =>
            (widget.id != other.id) &&
            _startTime.hour == other.startTime.hour &&
            _startTime.minute == other.startTime.minute)
        .isNotEmpty) {
      error = 'There\'s already a rate with this start time.';
    }

    if (basalRates
        .where((other) =>
            (widget.id != other.id) &&
            DateTimeUtils.convertTimeOfDayToDateTime(_startTime)
                .isBefore(other.startTime) &&
            DateTimeUtils.convertTimeOfDayToDateTime(_endTime)
                .isAfter(other.startTime))
        .isNotEmpty) {
      error = 'This rate\'s time period overlaps with another one.';
    }

    return error == null
        ? null
        : showDialog(
            context: context,
            builder: (BuildContext context) {
              return AlertDialog(
                content: Text(error!),
                actions: <Widget>[
                  TextButton(
                    onPressed: () => Navigator.pop(context, 'CANCEL'),
                    child: const Text('GO BACK TO EDITING'),
                  ),
                  ElevatedButton(
                    onPressed: () => Navigator.pop(context, 'CONFIRM'),
                    child: const Text('SAVE AS IS'),
                  ),
                ],
              );
            });
  }

  void handleSaveAction({bool next = true}) async {
    setState(() {
      _isSaving = true;
    });
    if (_basalForm.currentState!.validate()) {
      await validateTimePeriod().then((value) async {
        if (value != 'CANCEL') {
          Basal basal = Basal(
            id: widget.id,
            startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
            endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
            units: double.parse(_unitsController.text),
          );
          basal.basalProfile.targetId = widget.basalProfileId;
          Basal.put(basal);

          if (next) {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) {
                  return BasalDetailScreen(
                    basalProfileId: widget.basalProfileId,
                    suggestedStartTime: _endTime,
                    suggestedEndTime: widget.suggestedEndTime,
                  );
                },
              ),
            ).then((result) {
              Navigator.pop(
                context,
                ['New Basal Rate${result[1] != null ? 's' : ''} saved', basal] +
                    [result[1]],
              );
            });
          } else {
            Navigator.pop(
                context, ['${_isNew ? 'New' : ''} Basal Rate saved', basal]);
          }
        }
      });
    }
    setState(() {
      _isSaving = false;
    });
  }

  void handleCancelAction() {
    if (Settings.get().showConfirmationDialogOnCancel &&
        ((_isNew &&
                (_startTime.hour != (widget.suggestedStartTime?.hour ?? 0) ||
                    _endTime.hour != (widget.suggestedEndTime?.hour ?? 0) ||
                    _startTime.minute !=
                        (widget.suggestedStartTime?.minute ?? 0) ||
                    _endTime.minute != (widget.suggestedEndTime?.minute ?? 0) ||
                    double.tryParse(_unitsController.text) != 0)) ||
            (!_isNew &&
                (TimeOfDay.fromDateTime(_basal!.startTime) != _startTime ||
                    TimeOfDay.fromDateTime(_basal!.endTime) != _endTime ||
                    double.tryParse(_unitsController.text) !=
                        _basal!.units)))) {
      DialogUtils.showCancelConfirmationDialog(
        context: context,
        isNew: _isNew,
        onSave: handleSaveAction,
      );
    } else {
      Navigator.pop(context);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
            '${_isNew ? 'New' : 'Edit'} Basal Rate for ${BasalProfile.get(widget.basalProfileId)?.name}'),
      ),
      drawer: const Navigation(currentLocation: BasalDetailScreen.routeName),
      body: Scrollbar(
        controller: _scrollController,
        child: SingleChildScrollView(
          controller: _scrollController,
          child: Column(
            children: [
              FormWrapper(
                formState: _basalForm,
                fields: [
                  Row(
                    children: [
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.only(right: 5),
                          child: TimeOfDayFormField(
                            label: 'Start Time',
                            controller: _startTimeController,
                            time: _startTime,
                            onChanged: updateStartTime,
                          ),
                        ),
                      ),
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.only(left: 5),
                          child: TimeOfDayFormField(
                            label: 'End Time',
                            controller: _endTimeController,
                            time: _endTime,
                            onChanged: updateEndTime,
                          ),
                        ),
                      ),
                    ],
                  ),
                  NumberFormField(
                      controller: _unitsController,
                      label: 'Units',
                      suffix: 'U',
                      autoRoundToMultipleOfStep: true,
                      step: Settings.insulinSteps,
                      onChanged: (value) {
                        if (value != null) {
                          _unitsController.text =
                              Utils.toStringMatchingTemplateFractionPrecision(
                                  value, Settings.insulinSteps);
                        }
                      }),
                ],
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: DetailBottomRow(
        onCancel: handleCancelAction,
        onAction:
            _isSaving ? null : () => handleSaveAction(next: !_isFinalRate),
        onMiddleAction: _isSaving || _isFinalRate
            ? null
            : () => handleSaveAction(next: false),
        actionText: _isFinalRate ? 'SAVE & CLOSE' : 'NEXT',
        middleActionText: 'SAVE & CLOSE',
      ),
    );
  }
}
