import 'package:duration_picker/duration_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:habitrack_app/main.dart';
import 'package:intl/intl.dart';

abstract class SettingEntry extends StatefulWidget {
  const SettingEntry({required this.name, super.key});

  final String name;

  @override
  State<StatefulWidget> createState() => _SettingEntryState();

  dynamic getValue() {
    throw UnimplementedError();
  }

  void setValue(dynamic newValue) {
    throw UnimplementedError();
  }
}

class _SettingEntryState extends State<SettingEntry> {
  @override
  Widget build(BuildContext context) {
    return const Text('Abstract, not implemented');
  }
}

// ###############################TEXT#########################################
class SettingEntryText extends SettingEntry {
  SettingEntryText({
    required super.name,
    this.defaultValue = 'Some Text',
    super.key,
  }) {
    setValue(defaultValue);
  }

  final TextEditingController valueController = TextEditingController();
  final String defaultValue;

  @override
  State<SettingEntryText> createState() => _SettingEntryTextState();

  @override
  String getValue() {
    logger.i('GETTING VALUE ${valueController.text}');
    return valueController.text;
  }

  @override
  void setValue(dynamic newValue) {
    if (newValue is! String) {
      throw Exception('Value of SettingEntryText can only be a String!');
    }
    valueController.text = newValue;
  }
}

class _SettingEntryTextState extends State<SettingEntryText> {
  void monitorTextChange() {
    final text = widget.valueController.text;
    logger.i('TEXT: $text');
  }

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

    // Start listening to changes.
    widget.valueController.addListener(monitorTextChange);
  }

  @override
  void dispose() {
    // Clean up the controller when the widget is removed from the widget tree.
    // This also removes the _printLatestValue listener.
    widget.valueController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          alignment: AlignmentDirectional.bottomStart,
          margin: const EdgeInsets.only(top: 7.5, bottom: 7.5),

          // color: Colors.black,
          child: Text(
            widget.name,
            textAlign: TextAlign.left,
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                  color: Theme.of(context).colorScheme.onPrimaryContainer,
                  fontWeight: FontWeight.bold,
                  fontSize: 15,
                ),
          ),
        ),
        TextField(
          keyboardType: TextInputType.text,
          controller: widget.valueController,
        ),
      ],
    );
  }
}

// ###############################NUMERIC#######################################
class SettingEntryNumeric extends SettingEntry {
  SettingEntryNumeric({required super.name, int defaultValue = 0, super.key}) {
    setValue(defaultValue);
  }

  final TextEditingController valueController = TextEditingController();

  @override
  State<SettingEntryNumeric> createState() => _SettingEntryNumericState();

  @override
  int getValue() {
    return int.parse(valueController.text);
  }

  @override
  void setValue(dynamic newValue) {
    if (newValue is! int) {
      throw Exception('Value of SettingEntryNumeric can only be an integer!');
    }
    valueController.text = newValue.toString();
  }
}

class _SettingEntryNumericState extends State<SettingEntryNumeric> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(widget.name),
        TextField(
          keyboardType: TextInputType.number,
          controller: widget.valueController,
        ),
      ],
    );
  }
}

// ###############################SLIDER########################################
class SettingEntrySlider extends SettingEntry {
  SettingEntrySlider({
    required this.topValue,
    required this.divisions,
    required super.name,
    double defaultValue = 0.0,
    super.key,
  }) {
    setValue(defaultValue);
  }

  final double topValue;
  final int divisions;
  final value = DoubleSaver();

  @override
  State<SettingEntrySlider> createState() => _SettingEntrySliderState();

  @override
  double getValue() {
    return value.v;
  }

  @override
  void setValue(dynamic newValue) {
    if (newValue is! double) {
      throw Exception('Value of SettingEntrySlider can only be a Double!');
    }
    value.v = newValue;
  }
}

class DoubleSaver {
  double v = 0;
}

class _SettingEntrySliderState extends State<SettingEntrySlider> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Row(
          children: [
            //Expanded(flex: 2, child: Text(widget.name)),
            Text(widget.name),
            Text(' ${widget.getValue()}'),
          ],
        ),
        Row(
          children: [
            const Text('0 '),
            Expanded(
              child: Slider(
                value: widget.getValue(),
                divisions: widget.divisions,
                max: widget.topValue,
                onChanged: sliderChange,
              ),
            ),
            Text(' ${widget.topValue}'),
          ],
        ),
      ],
    );
  }

  void sliderChange(double newValue) {
    setState(() {
      widget.setValue(newValue);
    });
  }
}

// #############################DURATION#######################################

class IntSaver {
  IntSaver({this.v = 30});
  int v;
}

class SettingEntryDuration extends SettingEntry {
  SettingEntryDuration({
    required super.name,
    required this.defaultValue,
    super.key,
  }) {
    val = IntSaver(v: defaultValue);
  }
  final int defaultValue;
  late final IntSaver val;

  @override
  State<SettingEntryDuration> createState() => _SettingEntryDurationState();

  @override
  int getValue() {
    return val.v;
  }

  @override
  void setValue(dynamic newValue) {
    if (newValue is! int) {
      throw Exception('Value of SettingEntryDuration can only be a Double!');
    }
    val.v = newValue;
  }
}

class _SettingEntryDurationState extends State<SettingEntryDuration> {
  @override
  Widget build(BuildContext context) {
    final textCurrent =
        AppLocalizations.of(context)!.widgetSettings_durationPickerCurrent;
    return Column(
      children: [
        Container(
          alignment: AlignmentDirectional.bottomStart,
          margin: const EdgeInsets.only(top: 7.5, bottom: 7.5),
          child: Text(
            '$textCurrent ${widget.getValue()}m',
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                  color: Theme.of(context).colorScheme.onPrimaryContainer,
                  fontWeight: FontWeight.bold,
                  fontSize: 15,
                ),
          ),
        ),
        OutlinedButton(
          style: OutlinedButton.styleFrom(
            backgroundColor: Theme.of(context).colorScheme.primary,
          ),
          onPressed: () async {
            var resultingDuration = await showDurationPicker(
              context: context,
              initialTime: Duration(minutes: widget.val.v),
            );
            resultingDuration ??= Duration(minutes: widget.defaultValue);
            // ignore: use_build_context_synchronously
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Chose duration: ${resultingDuration.inMinutes}'),
              ),
            );
            widget.setValue(resultingDuration.inMinutes);
            setState(() {});
          },
          child: Text(
            AppLocalizations.of(context)!.widgetSettings_durationPickerButton,
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                  color: Theme.of(context).colorScheme.onPrimary,
                ),
          ),
        ),
      ],
    );
  }
}

// ###############################DATE#########################################
class DateSaver {
  DateTime v = DateTime.now();
}

class SettingEntryDate extends SettingEntry {
  SettingEntryDate({required super.name, DateTime? defaultValue, super.key}) {
    this.defaultValue = defaultValue ?? DateTime.now();
    setValue(defaultValue);
  }

  final date = DateSaver();

  late final DateTime defaultValue;

  @override
  State<SettingEntryDate> createState() => _SettingEntryDateState();

  @override
  DateTime getValue() {
    return date.v;
  }

  @override
  void setValue(dynamic newValue) {
    if (newValue is! DateTime) {
      throw Exception('Value of SettingEntryNumeric can only be a DateTime!');
    }
    date.v = newValue;
  }
}

class _SettingEntryDateState extends State<SettingEntryDate> {
  @override
  Widget build(BuildContext context) {
    final dateFormat = DateFormat('dd. MMMM');
    return Column(
      children: [
        Text(
          '${widget.name}: ${dateFormat.format(widget.date.v)} ',
          style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                color: Theme.of(context).colorScheme.primaryContainer,
              ),
        ),
        TextButton(
          onPressed: datePicker,
          child: const Text('Choose a date'),
        ),
      ],
    );
  }

  Future<void> datePicker() async {
    final pickedDate = await showDatePicker(
      context: context,
      initialDate: widget.date.v, //get today's date
      firstDate: DateTime.now(),
      //DateTime.now() - not to allow to choose before today.
      lastDate: DateTime(2101),
    );
    final cleanDate = pickedDate ?? widget.date.v;
    widget.setValue(cleanDate);
    setState(() {});
  }
}
