import 'package:diameter/components/detail.dart';
import 'package:diameter/components/forms/boolean_form_field.dart';
import 'package:diameter/components/forms/number_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/accuracy.dart';
import 'package:diameter/models/meal.dart';
import 'package:diameter/models/meal_category.dart';
import 'package:diameter/models/meal_portion_type.dart';
import 'package:diameter/models/meal_source.dart';
import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart';
import 'package:diameter/screens/accuracy_detail.dart';
import 'package:diameter/screens/meal/meal_category_detail.dart';
import 'package:diameter/screens/meal/meal_portion_type_detail.dart';
import 'package:diameter/screens/meal/meal_source_detail.dart';
import 'package:diameter/utils/utils.dart';
import 'package:flutter/material.dart';

class MealDetailScreen extends StatefulWidget {
  static const String routeName = '/meal';
  final int id;

  const MealDetailScreen({Key? key, this.id = 0}) : super(key: key);

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

class _MealDetailScreenState extends State<MealDetailScreen> {
  Meal? _meal;

  bool _isNew = true;
  bool _isSaving = false;
  bool _isExpanded = false;
  bool _setManually = false;

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

  final _valueController = TextEditingController(text: '');
  final _carbsRatioController = TextEditingController(text: '');
  final _portionSizeController = TextEditingController(text: '');
  final _carbsPerPortionController = TextEditingController(text: '');
  final _delayedBolusDurationController = TextEditingController(text: '');
  final _notesController = TextEditingController(text: '');

  double _delayedBolusPercentage = 0;

  MealSource? _mealSource;
  MealCategory? _mealCategory;
  MealPortionType? _mealPortionType;
  Accuracy? _portionSizeAccuracy;
  Accuracy? _carbsRatioAccuracy;

  final _mealSourceController = TextEditingController(text: '');
  final _mealCategoryController = TextEditingController(text: '');
  final _mealPortionTypeController = TextEditingController(text: '');
  final _portionSizeAccuracyController = TextEditingController(text: '');
  final _carbsRatioAccuracyController = TextEditingController(text: '');

  List<MealCategory> _mealCategories = [];
  List<MealPortionType> _mealPortionTypes = [];
  List<MealSource> _mealSources = [];
  List<Accuracy> _portionSizeAccuracies = [];
  List<Accuracy> _carbsRatioAccuracies = [];

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

    reload();

    _portionSizeAccuracies = Accuracy.getAllForPortionSize();
    _carbsRatioAccuracies = Accuracy.getAllForCarbsRatio();
    _mealCategories = MealCategory.getAll();
    _mealPortionTypes = MealPortionType.getAll();
    _mealSources = MealSource.getAll();

    if (_meal != null) {
      _valueController.text = _meal!.value;
      _carbsRatioController.text = (_meal!.carbsRatio ?? '').toString();
      _portionSizeController.text = (_meal!.portionSize ?? '').toString();
      _carbsPerPortionController.text =
          (_meal!.carbsPerPortion ?? '').toString();
      _delayedBolusPercentage = _meal!.delayedBolusPercentage ?? 0;
      _delayedBolusDurationController.text =
          (_meal!.delayedBolusDuration ?? '').toString();
      _notesController.text = _meal!.notes ?? '';

      _mealSource = _meal!.mealSource.target;
      _mealSourceController.text = (_mealSource ?? '').toString();
      _mealCategory = _meal!.mealCategory.target;
      _mealCategoryController.text = (_mealCategory ?? '').toString();
      _mealPortionType = _meal!.mealPortionType.target;
      _mealPortionTypeController.text = (_mealPortionType ?? '').toString();
      _portionSizeAccuracy = _meal!.portionSizeAccuracy.target;
      _portionSizeAccuracyController.text =
          (_portionSizeAccuracy ?? '').toString();
      _carbsRatioAccuracy = _meal!.carbsRatioAccuracy.target;
      _carbsRatioAccuracyController.text =
          (_carbsRatioAccuracy ?? '').toString();
    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    _valueController.dispose();
    _carbsRatioController.dispose();
    _portionSizeController.dispose();
    _carbsPerPortionController.dispose();
    _delayedBolusDurationController.dispose();
    _notesController.dispose();
    _mealSourceController.dispose();
    _mealCategoryController.dispose();
    _mealPortionTypeController.dispose();
    _portionSizeAccuracyController.dispose();
    _carbsRatioAccuracyController.dispose();
    super.dispose();
  }

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

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

  void updateCarbsRatioAccuracy(Accuracy? value) {
    setState(() {
      _carbsRatioAccuracy = value;
      _carbsRatioAccuracyController.text =
          (_carbsRatioAccuracy ?? '').toString();
    });
  }

  void updatePortionSizeAccuracy(Accuracy? value) {
    setState(() {
      _portionSizeAccuracy = value;
      _portionSizeAccuracyController.text =
          (_portionSizeAccuracy ?? '').toString();
    });
  }

  void updateMealCategory(MealCategory? value) {
    setState(() {
      _mealCategory = value;
      _mealCategoryController.text = (_mealCategory ?? '').toString();
    });
  }

  void updateMealPortionType(MealPortionType? value) {
    setState(() {
      _mealPortionType = value;
      _mealPortionTypeController.text = (_mealPortionType ?? '').toString();
    });
  }

  void handleSaveAction() async {
    setState(() {
      _isSaving = true;
    });
    if (_mealForm.currentState!.validate()) {
      Meal meal = Meal(
        id: widget.id,
        value: _valueController.text,
        carbsRatio: double.tryParse(_carbsRatioController.text),
        portionSize: double.tryParse(_portionSizeController.text),
        carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
        delayedBolusDuration:
            int.tryParse(_delayedBolusDurationController.text),
        delayedBolusPercentage: _delayedBolusPercentage,
        notes: _notesController.text,
      );
      meal.mealSource.target = _mealSource;
      meal.mealCategory.target = _mealCategory;
      meal.mealPortionType.target = _mealPortionType;
      meal.portionSizeAccuracy.target = _portionSizeAccuracy;
      meal.carbsRatioAccuracy.target = _carbsRatioAccuracy;

      Meal.put(meal);
      Navigator.pop(context, ['${_isNew ? 'New' : ''} Meal Saved', meal]);
    }
    setState(() {
      _isSaving = false;
    });
  }

  void handleCancelAction() {
    if (Settings.get().showConfirmationDialogOnCancel &&
        ((_isNew &&
                (_valueController.text != '' ||
                    _mealSource != null ||
                    _mealCategory != null ||
                    _mealPortionType != null ||
                    double.tryParse(_carbsRatioController.text) != null ||
                    double.tryParse(_portionSizeController.text) != null ||
                    double.tryParse(_carbsPerPortionController.text) != null ||
                    _carbsRatioAccuracy != null ||
                    _portionSizeAccuracy != null ||
                    int.tryParse(_delayedBolusDurationController.text) !=
                        null ||
                    _delayedBolusPercentage != 0 ||
                    _notesController.text != '')) ||
            (!_isNew &&
                (_valueController.text != _meal!.value ||
                    _mealSource != _meal!.mealSource.target ||
                    _mealCategory != _meal!.mealCategory.target ||
                    _mealPortionType != _meal!.mealPortionType.target ||
                    double.tryParse(_carbsRatioController.text) !=
                        _meal!.carbsRatio ||
                    double.tryParse(_portionSizeController.text) !=
                        _meal!.portionSize ||
                    double.tryParse(_carbsPerPortionController.text) !=
                        _meal!.carbsPerPortion ||
                    _carbsRatioAccuracy != _meal!.carbsRatioAccuracy.target ||
                    _portionSizeAccuracy != _meal!.portionSizeAccuracy.target ||
                    int.tryParse(_delayedBolusDurationController.text) !=
                        _meal!.delayedBolusDuration ||
                    _delayedBolusPercentage != _meal!.delayedBolusPercentage ||
                    _notesController.text != (_meal!.notes ?? ''))))) {
      DialogUtils.showCancelConfirmationDialog(
        context: context,
        isNew: _isNew,
        onSave: handleSaveAction,
      );
    } else {
      Navigator.pop(context);
    }
  }

  void onSelectMealSource(MealSource? mealSource) {
    setState(() {
      _mealSource = mealSource;
      _mealSourceController.text = (_mealSource ?? '').toString();
    });
    if (mealSource != null) {
      if (mealSource.defaultCarbsRatioAccuracy.hasValue) {
        updateCarbsRatioAccuracy(mealSource.defaultCarbsRatioAccuracy.target);
      }
      if (mealSource.defaultPortionSizeAccuracy.hasValue) {
        updatePortionSizeAccuracy(mealSource.defaultPortionSizeAccuracy.target);
      }
      if (mealSource.defaultMealCategory.hasValue) {
        updateMealCategory(mealSource.defaultMealCategory.target);
      }
      if (mealSource.defaultMealPortionType.hasValue) {
        updateMealPortionType(mealSource.defaultMealPortionType.target);
      }
    }
  }

  void calculateThirdMeasurementOfPortionCarbsRelation(
      {double? carbsRatioUpdate,
      double? portionSizeUpdate,
      double? carbsPerPortionUpdate}) {
    if (!_setManually) {
      double? carbsRatio =
        carbsRatioUpdate ?? double.tryParse(_carbsRatioController.text);
    double? portionSize =
        portionSizeUpdate ?? double.tryParse(_portionSizeController.text);
    double? carbsPerPortion = carbsPerPortionUpdate ??
        double.tryParse(_carbsPerPortionController.text);

    int toCalculate = 0;
    const calcCarbsRatio = 1;
    const calcCarbsPerPortion = 2;
    const calcPortionSize = 3;
    
    if (carbsRatioUpdate != null) {
      if (portionSize != null && portionSize != 0) {
        toCalculate = calcCarbsPerPortion;
      } else if (carbsPerPortion != null && carbsPerPortion != 0) {
        toCalculate = calcPortionSize;
      }
    } else if (portionSizeUpdate != null) {
      if (carbsRatio != null && carbsRatio != 0) {
        toCalculate = calcCarbsPerPortion;
      } else if (carbsPerPortion != null && carbsPerPortion != 0) {
        toCalculate = calcCarbsRatio;
      }
    } else if (carbsPerPortionUpdate != null) {
      if (carbsRatio != null && carbsRatio != 0) {
        toCalculate = calcPortionSize;
      } else if (portionSize != null && portionSize != 0) {
        toCalculate = calcCarbsRatio;
      }
    } else {
      if (carbsRatio != null && carbsRatio != 0) {
        if (portionSize != null && portionSize != 0) {
          toCalculate = calcCarbsPerPortion;
        } else if (carbsPerPortion != null && carbsPerPortion != 0) {
          toCalculate = calcPortionSize;
        }
      } else if (portionSize != null &&
          portionSize != 0 &&
          carbsPerPortion != null &&
          carbsPerPortion != 0) {
        toCalculate = calcCarbsRatio;
      }
    }

      setState(() {
        if (toCalculate == calcCarbsRatio) {
          _carbsRatioController.text =
              Utils.calculateCarbsRatio(carbsPerPortion!, portionSize!)
                  .toString();
        } else if (toCalculate == calcCarbsPerPortion) {
          _carbsPerPortionController.text = Utils.calculateCarbs(
                  carbsRatio!, portionSize!,
                  step: Settings.nutritionSteps)
              .toString();
        } else if (toCalculate == calcPortionSize) {
          _portionSizeController.text = Utils.calculatePortionSize(
                  carbsRatio!, carbsPerPortion!,
                  step: Settings.nutritionSteps)
              .toString();
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_isNew ? 'New Meal' : _meal!.value),
      ),
      drawer: const Navigation(currentLocation: MealDetailScreen.routeName),
      body: Scrollbar(
        controller: _scrollController,
        child: SingleChildScrollView(
          controller: _scrollController,
          child: Column(
            children: <Widget>[
              FormWrapper(
                formState: _mealForm,
                fields: [
                  TextFormField(
                    controller: _valueController,
                    decoration: const InputDecoration(
                      labelText: 'Name',
                    ),
                    validator: (value) {
                      if (value!.trim().isEmpty) {
                        return 'Empty name';
                      }
                      return null;
                    },
                  ),
                  Row(
                    children: [
                      Expanded(
                        child: AutoCompleteDropdownButton<MealSource>(
                          controller: _mealSourceController,
                          selectedItem: _mealSource,
                          label: 'Meal Source',
                          items: _mealSources,
                          onChanged: onSelectMealSource,
                        ),
                      ),
                      IconButton(
                        onPressed: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => _mealSource == null
                                  ? const MealSourceDetailScreen()
                                  : MealSourceDetailScreen(id: _mealSource!.id),
                            ),
                          ).then((result) {
                            onSelectMealSource(result?[1]);
                            reload(message: result?[0]);
                          });
                        },
                        icon:
                            Icon(_mealSource == null ? Icons.add : Icons.edit),
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Expanded(
                        child: AutoCompleteDropdownButton<MealPortionType>(
                          controller: _mealPortionTypeController,
                          selectedItem: _mealPortionType,
                          label: 'Meal Portion Type',
                          items: _mealPortionTypes,
                          onChanged: updateMealPortionType,
                        ),
                      ),
                      IconButton(
                        onPressed: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => _mealPortionType == null
                                  ? const MealPortionTypeDetailScreen()
                                  : MealPortionTypeDetailScreen(
                                      id: _mealPortionType!.id),
                            ),
                          ).then((result) {
                            updateMealPortionType(result?[1]);
                            reload(message: result?[0]);
                          });
                        },
                        icon: Icon(
                            _mealPortionType == null ? Icons.add : Icons.edit),
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Expanded(
                        child: NumberFormField(
                          label: 'Carbs ratio',
                          suffix: '%',
                          controller: _carbsRatioController,
                          showSteppers: false,
                          onChanged: (value) async {
                            await Future.delayed(const Duration(seconds: 1));
                            calculateThirdMeasurementOfPortionCarbsRelation(carbsRatioUpdate: value);
                          },
                        ),
                      ),
                      const SizedBox(width: 10),
                      Expanded(
                        child: NumberFormField(
                          label: 'Portion size',
                          suffix: Settings.nutritionMeasurementSuffix,
                          controller: _portionSizeController,
                          showSteppers: false,
                          onChanged: (value) async {
                            await Future.delayed(const Duration(seconds: 1));
                            calculateThirdMeasurementOfPortionCarbsRelation(portionSizeUpdate: value);
                          },
                        ),
                      ),
                      const SizedBox(width: 10),
                      Expanded(
                        child: NumberFormField(
                          label: 'Carbs per portion',
                          suffix: Settings.nutritionMeasurementSuffix,
                          controller: _carbsPerPortionController,
                          showSteppers: false,
                          onChanged: (value) async {
                            await Future.delayed(const Duration(seconds: 1));
                            calculateThirdMeasurementOfPortionCarbsRelation(carbsPerPortionUpdate: value);
                          },
                        ),
                      ),
                    ],
                  ),
                  Expanded(
                    child: BooleanFormField(
                      value: _setManually,
                      label: 'set carbs ratio manually',
                      onChanged: (value) {
                        setState(() {
                          _setManually = value;
                          calculateThirdMeasurementOfPortionCarbsRelation();
                        });
                      },
                    ),
                  ),
                  TextFormField(
                    controller: _notesController,
                    decoration: const InputDecoration(
                      labelText: 'Notes',
                    ),
                    keyboardType: TextInputType.multiline,
                    minLines: 2,
                    maxLines: 5,
                  ),
                  const Divider(),
                  Padding(
                    padding: const EdgeInsets.only(bottom: 10.0),
                    child: Row(
                      children: [
                        Text(
                          'BOLUS DELAY',
                          style: Theme.of(context).textTheme.subtitle2,
                        ),
                        const Spacer(),
                      ],
                    ),
                  ),
                  Row(
                    children: [
                      Expanded(
                        child: TextFormField(
                          decoration: const InputDecoration(
                            labelText: 'Duration',
                            suffixText: ' min',
                          ),
                          controller: _delayedBolusDurationController,
                          onChanged: (value) => setState(() {}),
                          keyboardType: const TextInputType.numberWithOptions(),
                        ),
                      ),
                      Expanded(
                        child: Slider(
                            label:
                                '${_delayedBolusPercentage.floor().toString()}%',
                            divisions: 100,
                            value: _delayedBolusPercentage,
                            min: 0,
                            max: 100,
                            onChanged:
                                _delayedBolusDurationController.text != ''
                                    ? (value) {
                                        setState(() {
                                          _delayedBolusPercentage = value;
                                        });
                                      }
                                    : null),
                      ),
                      const Text('%', textScaleFactor: 1.5),
                    ],
                  ),
                  const Divider(),
                  GestureDetector(
                    onTap: () => setState(() {
                      _isExpanded = !_isExpanded;
                    }),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      children: [
                        Expanded(
                          child: Text(
                            'ADDITIONAL FIELDS',
                            style: Theme.of(context).textTheme.subtitle2,
                          ),
                        ),
                        Icon(_isExpanded
                            ? Icons.expand_less
                            : Icons.expand_more),
                      ],
                    ),
                  ),
                  Column(
                    children: _isExpanded
                        ? [
                            Padding(
                              padding:
                                  const EdgeInsets.symmetric(vertical: 5.0),
                              child: Row(
                                children: [
                                  Expanded(
                                    child: AutoCompleteDropdownButton<
                                        MealCategory>(
                                      controller: _mealCategoryController,
                                      selectedItem: _mealCategory,
                                      label: 'Meal Category',
                                      items: _mealCategories,
                                      onChanged: updateMealCategory,
                                    ),
                                  ),
                                  IconButton(
                                    onPressed: () {
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) => _mealCategory ==
                                                  null
                                              ? const MealCategoryDetailScreen()
                                              : MealCategoryDetailScreen(
                                                  id: _mealCategory!.id),
                                        ),
                                      ).then((result) {
                                        updateMealCategory(result?[1]);
                                        reload(message: result?[0]);
                                      });
                                    },
                                    icon: Icon(_mealCategory == null
                                        ? Icons.add
                                        : Icons.edit),
                                  ),
                                ],
                              ),
                            ),
                            Padding(
                              padding:
                                  const EdgeInsets.symmetric(vertical: 5.0),
                              child: Row(
                                children: [
                                  Expanded(
                                    child: AutoCompleteDropdownButton<Accuracy>(
                                      controller:
                                          _portionSizeAccuracyController,
                                      selectedItem: _portionSizeAccuracy,
                                      label: 'Portion Size Accuracy',
                                      items: _portionSizeAccuracies,
                                      onChanged: updatePortionSizeAccuracy,
                                    ),
                                  ),
                                  IconButton(
                                    onPressed: () {
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) =>
                                              _portionSizeAccuracy == null
                                                  ? const AccuracyDetailScreen()
                                                  : AccuracyDetailScreen(
                                                      id: _portionSizeAccuracy!
                                                          .id),
                                        ),
                                      ).then((result) {
                                        updatePortionSizeAccuracy(result?[1]);
                                        reload(message: result?[0]);
                                      });
                                    },
                                    icon: Icon(_portionSizeAccuracy == null
                                        ? Icons.add
                                        : Icons.edit),
                                  ),
                                ],
                              ),
                            ),
                            Padding(
                              padding:
                                  const EdgeInsets.symmetric(vertical: 5.0),
                              child: Row(
                                children: [
                                  Expanded(
                                    child: AutoCompleteDropdownButton<Accuracy>(
                                      controller: _carbsRatioAccuracyController,
                                      selectedItem: _carbsRatioAccuracy,
                                      label: 'Carbs Ratio Accuracy',
                                      items: _carbsRatioAccuracies,
                                      onChanged: updateCarbsRatioAccuracy,
                                    ),
                                  ),
                                  IconButton(
                                    onPressed: () {
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) =>
                                              _carbsRatioAccuracy == null
                                                  ? const AccuracyDetailScreen()
                                                  : AccuracyDetailScreen(
                                                      id: _carbsRatioAccuracy!
                                                          .id),
                                        ),
                                      ).then((result) {
                                        updateCarbsRatioAccuracy(result?[1]);
                                        reload(message: result?[0]);
                                      });
                                    },
                                    icon: Icon(_carbsRatioAccuracy == null
                                        ? Icons.add
                                        : Icons.edit),
                                  ),
                                ],
                              ),
                            ),
                          ]
                        : [],
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: DetailBottomRow(
        onCancel: handleCancelAction,
        onAction: _isSaving ? null : handleSaveAction,
      ),
    );
  }
}
