import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:fforte/addCam/cam_widgets.dart';
import 'package:fforte/db_helper.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:intl/intl.dart';
import 'package:latlong2/latlong.dart';
import 'package:animations/animations.dart';
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';

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

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

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

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

  TextEditingController id = 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);

  String datumS = DateFormat('yyyy-MM-dd').format(DateTime.now());
  String kontDatS = DateFormat('yyyy-MM-dd').format(DateTime.now());
  String abbauDatS = DateFormat('yyyy-MM-dd').format(DateTime(2000));
  String ausVonS = DateFormat('yyyy-MM-dd').format(DateTime(2000));
  String ausBisS = DateFormat('yyyy-MM-dd').format(DateTime(2000));
  String protoAmS = DateFormat('yyyy-MM-dd').format(DateTime.now());
  DateTime? ausBis;
  DateTime? ausVon;
  DateTime? abbauDat;
  DateTime datum = DateTime.now();
  DateTime kontDat = DateTime.now();
  DateTime protoAm = DateTime.now();

  Map<String, dynamic> getPlace() {
    Map<String, dynamic> place = {
      'CID': id.text,
      'Rudel': rudelC.text,
      'Datum': datumS,
      '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': kontDatS,
      'AbbauDat': abbauDatS,
      'Auftrag': auftragC.text,
      'KontAbsp': kontAbspC.text,
      'SonstBem': sonstBemC.text,
      'FKontakt1': fKontakt1C.text,
      'FKontakt2': fKontakt2C.text,
      'FKontakt3': fKontakt3C.text,
      'Standort': standortC.text,
      'AusVon': ausVonS,
      'AusBis': ausBisS,
      'KTage1': kTage1C.text,
      'KTage2': kTage2C.text,
      'ProtoAm': protoAmS,
      '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.templateData != null) {
      id.text = widget.templateData!['CID'];
      rudelC.text = widget.templateData!['Rudel'];
      adresse1C.text = widget.templateData!['Adresse1'];
      adresse2C.text = widget.templateData!['Adresse2'];
      adresse3C.text = widget.templateData!['Adresse3'];
      bLandC.text = widget.templateData!['BLand'];
      lkrC.text = widget.templateData!['Lkr'];
      beiOrtC.text = widget.templateData!['BeiOrt'];
      ortInfoC.text = widget.templateData!['OrtInfo'];
      selectedStatus = widget.templateData!['Status'];
      selectedSTTyp = widget.templateData!['STTyp'];
      ffTypC.text = widget.templateData!['FFTyp'];
      selectedFotoFilm = widget.templateData!['FotoFilm'];
      selectedMEZ = widget.templateData!['MEZ'];
      selectedPlatzung = widget.templateData!['Platzung'];
      kSchloNrC.text = widget.templateData!['KSchloNr'];
      selectedBearsafe = widget.templateData!['Bearsafe'];
      datumS = widget.templateData!['Datum'];
      kontDatS = widget.templateData!['KontDat'];
      abbauDatS = widget.templateData!['AbbauDat'];
      auftragC.text = widget.templateData!['Auftrag'];
      kontAbspC.text = widget.templateData!['KontAbsp'];
      sonstBemC.text = widget.templateData!['SonstBem'];
      fKontakt1C.text = widget.templateData!['FKontakt1'];
      fKontakt2C.text = widget.templateData!['FKontakt2'];
      fKontakt3C.text = widget.templateData!['FKontakt3'];
      standortC.text = widget.templateData!['Standort'];
      ausVonS = widget.templateData!['AusVon'];
      ausBisS = widget.templateData!['AusBis'];
      kTage1C.text = widget.templateData!['KTage1'].toString();
      kTage2C.text = widget.templateData!['KTage2'].toString();
      protoAmS = widget.templateData!['ProtoAm'];
      intKommC.text = widget.templateData!['IntKomm'];
      betreuungC.text = widget.templateData!['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) {
          var dialogContext = 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 {
                    saveFile();
                    _httpRequest();
                      Navigator.pushNamedAndRemoveUntil(
                          // ignore: use_build_context_synchronously
                          context,
                          '/home',
                          (route) => false);
                  },
                  child: Text(AppLocalizations.of(context)!.sendtoserver)),
              TextButton(
                  onPressed: () async {
                    saveData();
                    await saveFile();
                    // ignore: use_build_context_synchronously
                    Navigator.pushNamedAndRemoveUntil(
                        // ignore: use_build_context_synchronously
                        context,
                        '/home',
                        (route) => false);
                  },
                  child: Text(AppLocalizations.of(context)!.saveasfile)),
              TextButton(onPressed: () {
                Navigator.pop(dialogContext);
              }, child: Text(AppLocalizations.of(context)!.cancel)),
            ],
          );
        });
  }

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

    // print(jsonEncode(place));

    final dio = Dio();
    final SharedPreferences prefs = await SharedPreferences.getInstance();

    dio.options.responseType = ResponseType.plain;
    Response response =
        Response(requestOptions: RequestOptions(path: ''), statusCode: 400);

    try {
      response = await dio.post(prefs.getString('apiAddress') ?? "",
          data: jsonEncode(place));
    } on DioException catch (e) {
      if (e.response?.statusCode == 500) {
/*         print('-------------------------');
        print('code 500'); */
        return;
      }
    }
    if (response.statusCode == 201) {
      // print(response.statusCode);
      var placeDB = DBHelper();

      await placeDB.updateSent();
    } else {
      //print(response.statusCode);
    }
  }

  Future<void> saveFile() async {
    String? selectedDirectory = await FilePicker.platform.getDirectoryPath();

    Map place = getPlace();

    String jsonPlace = jsonEncode(place);

    if (selectedDirectory == null) {
      return;
    }

    File file = File('$selectedDirectory/cam-${id.text}.txt');

    await file.writeAsString(jsonPlace);

    // ignore: use_build_context_synchronously
    ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Datei gespeichert in $selectedDirectory')));
  }

  // 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': id,
      '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.isEmpty) 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);
  }

  // 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() => [
          Step(
              title: Text(AppLocalizations.of(context)!.firstStep),
              content: Column(
                children: [
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Standort(standortC: standortC),
                  ),
                  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;
                      });
                    },
                  ),
                  Betreuung(betreuungC: betreuungC),
                  const SizedBox(
                    height: 20,
                  ),
                  CamId(id: id),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: FFTyp(ffTypC: ffTypC),
                  ),
                  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,
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: KSchloNr(kSchloNrC: kSchloNrC),
                  ),
                  const SizedBox(
                    height: 5,
                  ),
                  Rudel(rudelC: rudelC),
                  const SizedBox(
                    height: 15,
                  ),
                ],
              )),

          // Second step (location)
          Step(
              title: Text(AppLocalizations.of(context)!.locations),
              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(
                              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)),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: BLand(bLandC: bLandC),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Lkr(lkrC: lkrC),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: BeiOrt(beiOrtC: beiOrtC),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: OrtInfo(ortInfoC: ortInfoC),
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.platzung),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          )
                        ],
                      )),
                  Platzung(
                    initialPlatzung: selectedPlatzung,
                    onPlatzungChanged: (platzung) {
                      setState(() {
                        selectedPlatzung = platzung;
                      });
                    },
                  ),
                ],
              )),
          // Date Step
          Step(
              title: Text(AppLocalizations.of(context)!.date),
              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),
                        ),
                      ],
                    ),
                  ),
                  KTage1(kTage1C: kTage1C),
                  const SizedBox(
                    height: 20,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Row(
                        children: [
                          Text(AppLocalizations.of(context)!.ktage2),
                          const Text(
                            '*',
                            style: TextStyle(color: Colors.red),
                          )
                        ],
                      )),
                  KTage2(kTage2C: kTage2C),
                  const SizedBox(
                    height: 20,
                  ),
                  AbbauDat(abbauDat: abbauDat),
                  AusVon(ausVon: ausVon),
                  AusBis(ausBis: ausBis),
                  const SizedBox(
                    height: 20,
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Auftrag(auftragC: auftragC),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: KontAbsp(kontAbspC: kontAbspC),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child:
                        SonstBem(sonstBemC: sonstBemC),
                  ),
                ],
              )),
          Step(
              title: Text(AppLocalizations.of(context)!.kontakt),
              content: Column(
                children: [
                  const SizedBox(
                    height: 15,
                  ),
                  Align(
                      alignment: Alignment.bottomLeft,
                      child: Adresse1(adresse1C: adresse1C)),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Adresse2(adresse2C: adresse2C),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: Adresse3(adresse3C: adresse3C),
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: FKontakt1(fKontakt1C: fKontakt1C),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: FKontakt2(fKontakt2C: fKontakt2C),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: FKontakt3(fKontakt3C: fKontakt3C),
                  ),
                  Align(
                    alignment: Alignment.bottomLeft,
                    child: IntKomm(intKommC: intKommC),
                  ),
                ],
              ))
        ];

    // Here the site is built inclusive 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;
                    });
                  }
                })));
  }
}
