import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:fforte/addCam/cam_widgets.dart';
import 'package:fforte/other/db_helper.dart';
import 'package:fforte/other/methods.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
import 'package:animations/animations.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AddCamMain extends StatefulWidget {
  final bool isTemplate;
  final bool isFinished;
  final Map<String, dynamic>? existingData;

  const AddCamMain({super.key, this.isTemplate = false, this.existingData, this.isFinished = false});

  @override
  State<AddCamMain> createState() => _AddCamMainState();
}

class _AddCamMainState extends State<AddCamMain> {
  // var declaration
  int currentStep = 0;
  // bool isTemplate = false;

  TextEditingController cid = TextEditingController();
  TextEditingController rudelC = TextEditingController();
  TextEditingController adresse1C = TextEditingController();
  TextEditingController adresse2C = TextEditingController();
  TextEditingController adresse3C = TextEditingController();
  TextEditingController bLandC = TextEditingController();
  TextEditingController lkrC = TextEditingController();
  TextEditingController beiOrtC = TextEditingController();
  TextEditingController ortInfoC = TextEditingController();
  TextEditingController ffTypC = TextEditingController();
  TextEditingController kSchloNrC = TextEditingController();
  TextEditingController auftragC = TextEditingController();
  TextEditingController kontAbspC = TextEditingController();
  TextEditingController sonstBemC = TextEditingController();
  TextEditingController fKontakt1C = TextEditingController();
  TextEditingController fKontakt2C = TextEditingController();
  TextEditingController fKontakt3C = TextEditingController();
  TextEditingController standortC = TextEditingController();
  TextEditingController kTage1C = TextEditingController();
  TextEditingController kTage2C = TextEditingController();
  TextEditingController intKommC = TextEditingController();
  TextEditingController betreuungC = TextEditingController();

  String selectedStatus = 'aktiv';
  String selectedSTTyp = 'opportunistisch';
  String selectedFotoFilm = 'Foto';
  String selectedMEZ = 'Sommerzeit';
  String selectedPlatzung = 'Kirrung';
  String selectedBearsafe = 'Nein';

  Position currentPosition = Position(
      longitude: 10.0,
      latitude: 51.0,
      timestamp: DateTime.now(),
      accuracy: 0.0,
      altitude: 0.0,
      heading: 0.0,
      speed: 0.0,
      speedAccuracy: 0.0,
      altitudeAccuracy: 0.0,
      headingAccuracy: 0.0);

  DateTime? abbauDat;
  DateTime datum = DateTime.now();
  DateTime kontDat = DateTime.now();
  DateTime protoAm = DateTime.now();

  Map<String, dynamic> getPlace() {
    Map<String, dynamic> place = {
      'ID': widget.existingData?['ID'],
      'CID': cid.text,
      'Rudel': rudelC.text,
      'Datum': datum.toString().split(" ").first,
      'Adresse1': adresse1C.text,
      'Adresse2': adresse2C.text,
      'Adresse3': adresse3C.text,
      'BLand': bLandC.text,
      'Lkr': lkrC.text,
      'BeiOrt': beiOrtC.text,
      'OrtInfo': ortInfoC.text,
      'Status': selectedStatus,
      'STTyp': selectedSTTyp,
      'FFTyp': ffTypC.text,
      'FotoFilm': selectedFotoFilm,
      'MEZ': selectedMEZ,
      'Platzung': selectedPlatzung,
      'KSchloNr': kSchloNrC.text,
      'Bearsafe': selectedBearsafe,
      'KontDat': kontDat.toString().split(" ").first,
      'AbbauDat': abbauDat.toString().split(" ").first.replaceAll("null", ""),
      'Auftrag': auftragC.text,
      'KontAbsp': kontAbspC.text,
      'SonstBem': sonstBemC.text,
      'FKontakt1': fKontakt1C.text,
      'FKontakt2': fKontakt2C.text,
      'FKontakt3': fKontakt3C.text,
      'Standort': standortC.text,
      'KTage1': kTage1C.text,
      'KTage2': kTage2C.text,
      'ProtoAm': protoAm.toString().split(" ").first,
      'IntKomm': intKommC.text,
      'Betreuung': betreuungC.text,
      'DECLNG': currentPosition.longitude,
      'DECLAT': currentPosition.latitude,
    };

    return place;
  }

  bool empty = false;

  // determine live position with checks for denied permission and turned off location service
  Future<Position> _deteterminePosition() async {
    bool locationEnabled;
    LocationPermission permissionGiven;

    locationEnabled = await Geolocator.isLocationServiceEnabled();
    if (!locationEnabled) {
      // ignore: use_build_context_synchronously
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          // ignore: use_build_context_synchronously
          content: Text(AppLocalizations.of(context)!.locationDisabled)));
      return currentPosition;
    }

    permissionGiven = await Geolocator.checkPermission();
    if (permissionGiven == LocationPermission.denied) {
      permissionGiven = await Geolocator.requestPermission();
      if (permissionGiven == LocationPermission.denied) {
        // ignore: use_build_context_synchronously
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
            // ignore: use_build_context_synchronously
            content: Text(AppLocalizations.of(context)!.locationForbidden)));

        return currentPosition;
      }
    }

    if (permissionGiven == LocationPermission.deniedForever) {
      // ignore: use_build_context_synchronously
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          // ignore: use_build_context_synchronously
          content: Text(AppLocalizations.of(context)!.locationForbidden)));
      return currentPosition;
    }
    return currentPosition = await Geolocator.getCurrentPosition();
  }

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

    // updates the currentPosition var after the _determine position has finished. Means user view updates with his live location
    _deteterminePosition().then((position) {
      setState(() {
        currentPosition = position;
      });
    });

    // If a template is edited this fills in the existing values
    if (widget.isTemplate || widget.isFinished && widget.existingData != null) {
      cid.text = widget.existingData!['CID'];
      rudelC.text = widget.existingData!['Rudel'];
      adresse1C.text = widget.existingData!['Adresse1'];
      adresse2C.text = widget.existingData!['Adresse2'];
      adresse3C.text = widget.existingData!['Adresse3'];
      bLandC.text = widget.existingData!['BLand'];
      lkrC.text = widget.existingData!['Lkr'];
      beiOrtC.text = widget.existingData!['BeiOrt'];
      ortInfoC.text = widget.existingData!['OrtInfo'];
      selectedStatus = widget.existingData!['Status'];
      selectedSTTyp = widget.existingData!['STTyp'];
      ffTypC.text = widget.existingData!['FFTyp'];
      selectedFotoFilm = widget.existingData!['FotoFilm'];
      selectedMEZ = widget.existingData!['MEZ'];
      selectedPlatzung = widget.existingData!['Platzung'];
      kSchloNrC.text = widget.existingData!['KSchloNr'];
      selectedBearsafe = widget.existingData!['Bearsafe'];
      datum = DateTime.parse(widget.existingData!['Datum']);
      kontDat = DateTime.parse(widget.existingData!['KontDat']);
      abbauDat = widget.existingData!['AbbauDat'] == "" ? null : DateTime.parse(widget.existingData!['AbbauDat']);
      auftragC.text = widget.existingData!['Auftrag'];
      kontAbspC.text = widget.existingData!['KontAbsp'];
      sonstBemC.text = widget.existingData!['SonstBem'];
      fKontakt1C.text = widget.existingData!['FKontakt1'];
      fKontakt2C.text = widget.existingData!['FKontakt2'];
      fKontakt3C.text = widget.existingData!['FKontakt3'];
      standortC.text = widget.existingData!['Standort'];
      kTage1C.text = widget.existingData!['KTage1'].toString();
      kTage2C.text = widget.existingData!['KTage2'].toString();
      protoAm = DateTime.parse(widget.existingData!['ProtoAm']);
      intKommC.text = widget.existingData!['IntKomm'];
      betreuungC.text = widget.existingData!['Betreuung'];
    }
  }

  // Function to show the dialog where the user has to choose if he want to safe his values as a template
  Future<void> showTemplateDialog(List<String> emptyField) async {
    return showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text(AppLocalizations.of(context)!.fieldEmpty),
            content: SingleChildScrollView(
              child: ListBody(children: <Widget>[Text(emptyField.join("; "))]),
            ),
            actions: <Widget>[
              TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text(AppLocalizations.of(context)!.cancel)),
              TextButton(
                  onPressed: () {
                    saveTemplate();
                    Navigator.pushNamedAndRemoveUntil(
                        context, '/home', (route) => false);
                  },
                  child: Text(AppLocalizations.of(context)!.template))
            ],
          );
        });
  }

  Future<void> showSaveOptionsDialog() async {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text(AppLocalizations.of(context)!.savemethod),
            actions: [
              TextButton(
                  onPressed: () async {
                    saveTemplate();
                    Navigator.pushNamedAndRemoveUntil(
                        // ignore: use_build_context_synchronously
                        context,
                        '/home',
                        (route) => false);
                  },
                  child: Text(AppLocalizations.of(context)!.template)),
              TextButton(
                  onPressed: () async {
                    _httpRequest();
                    saveData();
                    Navigator.pushNamedAndRemoveUntil(
                        // ignore: use_build_context_synchronously
                        context,
                        '/home',
                        (route) => false);
                  },
                  child: Text(AppLocalizations.of(context)!.sendtoserver)),
              TextButton(
                  onPressed: () async {
                    saveData();
                    saveFile();
                    // ignore: use_build_context_synchronously
                  },
                  child: Text(AppLocalizations.of(context)!.saveasfile)),
              TextButton(
                onPressed: () {
                  saveData();
                    Navigator.pushNamedAndRemoveUntil(
                        // ignore: use_build_context_synchronously
                        context,
                        '/home',
                        (route) => false);
              }, child: Text(AppLocalizations.of(context)!.justsave)),
              TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: Text(AppLocalizations.of(context)!.cancel)),
            ],
          );
        });
  }



  void _httpRequest() async {
    Map<String, dynamic> place = getPlace();

    Methods(jsonEncode(place)).httpRequest();

  }

  Future<void> saveFile() async {
    String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
    SharedPreferences prefs = await SharedPreferences.getInstance();
    Map place = getPlace();
    String jsonPlace = jsonEncode(place);

    if (selectedDirectory == null) {
      // ignore: use_build_context_synchronously
      Navigator.pop(context);
      return;
    }
    await prefs.setString('saveDir', selectedDirectory);

    // ignore: use_build_context_synchronously
    File file = File('$selectedDirectory/${AppLocalizations.of(context)!.justplace}-${standortC.text}.txt');

    try {
      await file.writeAsString(jsonPlace);
    } catch (e) {
      // ignore: use_build_context_synchronously
      Navigator.pop(context);
      // ignore: use_build_context_synchronously
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          // ignore: use_build_context_synchronously
          content: Text(AppLocalizations.of(context)!.savefilefailed)));
      return;
    }
    // ignore: use_build_context_synchronously
    ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Datei gespeichert in $selectedDirectory')));

    Navigator.pushNamedAndRemoveUntil(
        // ignore: use_build_context_synchronously
        context,
        '/home',
        (route) => false);
  }

  // checks if required fields are not empty. If one is the name will be returned
  List<String> validateData() {
    List<String> emptyFields = <String>[];

    Map<String, TextEditingController> fields = {
      'CID': cid,
      'Rudel': rudelC,
      'Adresse1': adresse1C,
      'BLand': bLandC,
      'Lkr': lkrC,
      'BeiOrt': beiOrtC,
      'Status': TextEditingController(text: selectedStatus),
      'STTyp': TextEditingController(text: selectedSTTyp),
      'FFTyp': ffTypC,
      'FotoFilm': TextEditingController(text: selectedFotoFilm),
      'MEZ': TextEditingController(text: selectedMEZ),
      'Platzung': TextEditingController(text: selectedPlatzung),
      'KTage1': kTage1C,
      'KTage2': kTage2C,
      'Standort': standortC,
    };

    for (var entry in fields.entries) {
      if (entry.value.text.isEmpty) {
        emptyFields.add(entry.key);
      }
    }

    if (emptyFields.isNotEmpty) empty = true;

    return emptyFields;
  }

  // If the user decides to safe his values as a template this function is called to save the values in the database
  // If the user already edits a template this template will be upadted otherwise a new one will be created
  void saveTemplate() async {
    var placeDB = DBHelper();

    Map<String, dynamic> templates = getPlace();

    if (widget.isTemplate) {
      await placeDB.updateTemplate(templates);
    } else {
      await placeDB.addTemplate(templates);
    }
  }

  // If the user has filled all needed values this function will be called to safe them in the database
  // * also creates a json string to send it to the server later
  void saveData() async {
    var placeDB = DBHelper();

    Map<String, dynamic> place = getPlace();

    await placeDB.addPlace(place);

    if (widget.isTemplate) {
      await placeDB.deleteTemplate(cid.text);
    }
  }

  // The widget tree which gets the shown widget from the ./cam_widgets.dart file
  // The names of the widgets should be self-explaining
  @override
  Widget build(BuildContext context) {
    // List with the steps. The steps itself will be "shown" later
    List<Step> getSteps() => [
          // First step
          Step(
              title: Text(AppLocalizations.of(context)!.firststep),
              content: Column(
                children: [
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: VarTextField(
                      required: true,
                      dbName: "Standort",
                      textController: standortC,
                      localization: AppLocalizations.of(context)!.altstort,
                    ),
                  ),
                  const SizedBox(
                    height: 1,
                  ),
                  STTyp(
                    initialSTTyp: selectedSTTyp,
                    onSTTypChanged: (sttyp) {
                      setState(() {
                        selectedSTTyp = sttyp;
                      });
                    },
                  ),
                  const SizedBox(
                    height: 5,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.status),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          ),
                        ],
                      )),
                  Status(
                    initialStatus: selectedStatus,
                    onStatusChanged: (status) {
                      setState(() {
                        selectedStatus = status;
                      });
                    },
                  ),
                  VarTextField(
                      textController: betreuungC,
                      localization: AppLocalizations.of(context)!.betreuung,
                      dbName: "KontSum",
                      required: false),
                  const SizedBox(
                    height: 20,
                  ),
                  VarTextField(
                      textController: cid,
                      localization: AppLocalizations.of(context)!.camLink,
                      dbName: "CID",
                      required: true),
                  VarTextField(
                      textController: ffTypC,
                      localization: AppLocalizations.of(context)!.fftyp,
                      dbName: "FFTyp",
                      required: true),
                  const SizedBox(
                    height: 15,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.zeiteinstellung),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          )
                        ],
                      )),
                  MEZ(
                    initialMEZ: selectedMEZ,
                    onMEZChanged: (mez) {
                      setState(() {
                        selectedMEZ = mez;
                      });
                    },
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.bearsafe),
                        ],
                      )),
                  Bearsafe(
                    initialBearsafe: selectedBearsafe,
                    onBearsafeChanged: (bearsafe) {
                      setState(() {
                        selectedBearsafe = bearsafe;
                      });
                    },
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  VarTextField(
                      textController: kSchloNrC,
                      localization: AppLocalizations.of(context)!.kschlonr,
                      dbName: "KSchloNr",
                      required: false),
                  const SizedBox(
                    height: 5,
                  ),
                  VarTextField(
                      textController: rudelC,
                      localization: AppLocalizations.of(context)!.rudel,
                      dbName: "Rudel",
                      required: true),
                  const SizedBox(
                    height: 15,
                  ),
                ],
              )),

          // Second step
          Step(
              title: Text(AppLocalizations.of(context)!.secondstep),
              content: Column(
                children: [
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Text(currentPosition.latitude.toString())),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Text(currentPosition.longitude.toString())),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: ElevatedButton(
                        onPressed: () async {
                          final result = await Navigator.of(context)
                              .push<LatLng>(
                                  MaterialPageRoute(builder: (context) {
                            return Karte(
                              beiOrtC: beiOrtC,
                              currentPosition: currentPosition,
                              onPositionChange: (updatedPosition) {
                                setState(() {
                                  currentPosition = updatedPosition;
                                });
                              },
                            );
                          }));
                          if (result != null) {
                            setState(() {
                              currentPosition = Position(
                                latitude: result.latitude,
                                longitude: result.longitude,
                                timestamp: DateTime.now(),
                                accuracy: 0.0,
                                altitude: 0.0,
                                altitudeAccuracy: 0.0,
                                heading: 0.0,
                                headingAccuracy: 0.0,
                                speed: 0.0,
                                speedAccuracy: 0.0,
                              );
                            });
                          }
                        },
                        child: Text(AppLocalizations.of(context)!.openMap)),
                  ),
                  VarTextField(
                    textController: bLandC,
                    localization: AppLocalizations.of(context)!.bland,
                    dbName: "BLand",
                    required: true,
                    default_value: "bLand",
                  ),
                  VarTextField(
                      textController: lkrC,
                      localization: AppLocalizations.of(context)!.lkr,
                      dbName: "Lkr",
                      required: true),
                  VarTextField(
                      textController: beiOrtC,
                      localization: AppLocalizations.of(context)!.beiort,
                      dbName: "BeiOrt",
                      required: true),
                  VarTextField(
                      textController: ortInfoC,
                      localization: AppLocalizations.of(context)!.ortinfo,
                      dbName: "OrtInfo",
                      required: false),
                  const SizedBox(
                    height: 15,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.platzung),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          )
                        ],
                      )),
                  Platzung(
                    onPlatzungChanged: (platzung) {
                      setState(() {
                        selectedPlatzung = platzung;
                      });
                    },
                  ),
                ],
              )),
          // Third step
          Step(
              title: Text(AppLocalizations.of(context)!.thirdstep),
              content: Column(
                children: [
                  Datum(
                    datum: datum,
                  ),
                  KontDat(kontDat: kontDat),
                  const SizedBox(
                    height: 20,
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Row(
                      children: [
                        Text(AppLocalizations.of(context)!.ktage1),
                        const Text(
                          '*',
                          style: TextStyle(color: Colors.red),
                        ),
                      ],
                    ),
                  ),
                  VarTextField(
                    textController: kTage1C,
                    localization: AppLocalizations.of(context)!.ktage1,
                    dbName: "KTage1",
                    required: true,
                    default_value: "kTage1",
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.ktage2),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          )
                        ],
                      )),
                  VarTextField(
                    textController: kTage2C,
                    localization: AppLocalizations.of(context)!.ktage2,
                    dbName: "KTage1",
                    required: true,
                    default_value: "kTage2",
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  Row(
                    children: [
                      AbbauDat(abbauDat: abbauDat),
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  VarTextField(
                      textController: auftragC,
                      localization: AppLocalizations.of(context)!.auftrag,
                      dbName: "Auftrag",
                      required: false),
                  VarTextField(
                      textController: kontAbspC,
                      localization: AppLocalizations.of(context)!.kontabsp,
                      dbName: "KontAbsp",
                      required: false),
                  VarTextField(
                      textController: sonstBemC,
                      localization:
                          AppLocalizations.of(context)!.sonstbemerkungen,
                      dbName: "SonstBem",
                      required: false),
                ],
              )),
          // Fourth step
          Step(
              title: Text(AppLocalizations.of(context)!.fourthstep),
              content: Column(
                children: [
                  VarTextField(
                    textController: adresse1C,
                    localization: AppLocalizations.of(context)!.adresse1,
                    dbName: "Adresse1",
                    required: true,
                    default_value: "addresse1",
                  ),
                  VarTextField(
                      textController: adresse2C,
                      localization: AppLocalizations.of(context)!.adresse2,
                      dbName: "Adresse2",
                      required: false),
                  VarTextField(
                      textController: adresse3C,
                      localization: AppLocalizations.of(context)!.adresse3,
                      dbName: "Adresse2",
                      required: false),
                  const SizedBox(
                    height: 15,
                  ),
                  VarTextField(
                      textController: fKontakt1C,
                      localization: AppLocalizations.of(context)!.fkontakt1,
                      dbName: "FKontakt1",
                      required: false),
                  VarTextField(
                      textController: fKontakt2C,
                      localization: AppLocalizations.of(context)!.fkontakt2,
                      dbName: "FKontakt2",
                      required: false),
                  VarTextField(
                      textController: fKontakt3C,
                      localization: AppLocalizations.of(context)!.fkontakt3,
                      dbName: "FKontakt3",
                      required: false),
                  VarTextField(
                      textController: intKommC,
                      localization: AppLocalizations.of(context)!.intkomm,
                      dbName: "IntKomm",
                      required: false),
                ],
              ))
        ];

    // Here the site is built with the steps from above
    return Scaffold(
        appBar: AppBar(title: Text(AppLocalizations.of(context)!.addplace)),
        body: PageTransitionSwitcher(
            duration: const Duration(milliseconds: 800),
            transitionBuilder: (Widget child, Animation<double> animation,
                Animation<double> secondaryAnimation) {
              return SharedAxisTransition(
                animation: animation,
                secondaryAnimation: secondaryAnimation,
                transitionType: SharedAxisTransitionType.vertical,
                child: child,
              );
            },
            child: Stepper(
                key: ValueKey<int>(currentStep),
                type: StepperType.vertical,
                steps: getSteps(),

                // Functions that handle the navigation through the steps
                currentStep: currentStep,
                onStepTapped: (value) {
                  setState(() {
                    currentStep = value;
                  });
                },
                onStepContinue: () async {
                  final isLastStep = currentStep == getSteps().length - 1;

                  if (!isLastStep) {
                    saveTemplate();
                    setState(() {
                      currentStep += 1;
                    });
                  } else {
                    List<String> emptyFields = validateData();
                    // ! always filled out
                    empty = false;
                    if (empty == true) {
                      showTemplateDialog(emptyFields);
                      return;
                    } else if (empty == false) {
                      await showSaveOptionsDialog();
                    }
                  }
                },
                onStepCancel: () {
                  if (currentStep == 0) {
                    Navigator.pop(context);
                  } else {
                    setState(() {
                      currentStep -= 1;
                    });
                  }
                })));
  }
}
