import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:flutter_map/flutter_map.dart';
// import 'package:flutter_map_geojson/flutter_map_geojson.dart';
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:location/location.dart';
import 'package:latlong2/latlong.dart';
import 'package:nmea/nmea.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'
    as permission_handler;
import 'package:share_plus/share_plus.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:terepi_seged/controls/geoid_grid.dart';
import 'package:terepi_seged/eov/convert_coordinate.dart';
import 'package:terepi_seged/eov/eov.dart';
import 'package:terepi_seged/gnss_sentences/gngga.dart';
import 'package:terepi_seged/gnss_sentences/gngst.dart';
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
import 'package:terepi_seged/models/point_to_measure.dart';
import 'package:terepi_seged/models/point_with_description_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:terepi_seged/pages/map/presentation/views/measured_points_table_dialog.dart';
import 'package:terepi_seged/services/coord_converter_service.dart';

class MapViewController extends GetxController {
  // String gpsAddress = "E8:31:CD:14:8B:B2";
  // String gpsAddress = "98:CD:AC:62:FF:4E";
  RxString gpsAddress = "98:CD:AC:62:FF:36".obs;
  RxString gpsName = "TiGNSS Rover-FF4E".obs;
  // String gpsName = "TiGNSS Rover-8BB2";
  static const double maxZoomValue = 25.0;
  Rx<bool> gpsIsConnected = false.obs;
  RxBool ntripIsConnected = false.obs;
  RxInt ntripDataPacketNumbers = 0.obs;
  RxInt ggaSenDataPacketNumber = 0.obs;
  RxString ggaSendLastTimeStr = "".obs;
  String _messageBuffer = "";
  late BluetoothConnection connection;
  late Socket socket;
  late StreamSubscription socketStreamSubscription;
  RxInt gpsReceivedData = 0.obs;
  RxBool hasGpsValidData = false.obs;
  RxBool isMapMoveToCenter = true.obs;
  DateTime lastGpsRefreshTime = DateTime.now();
  String utcOfPositionFix = "";
  String utcDateOfPositionFix = "";
  RxInt ntripReceivedData = 0.obs;
  final NmeaDecoder nmeaDecoder = NmeaDecoder();
  String lastGgaMessage = '';
  DateTime lastSendTimeGgaMessage =
      DateTime.now().add(const Duration(seconds: -30));

  NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
  NumberFormat formatEovZ = NumberFormat("###0.0", "hu-HU");
  NumberFormat formatAltitudeError = NumberFormat("####0.000", "hu-HU");
  NumberFormat formatEovForFile = NumberFormat("#####0.0", "hu-HU");
  NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');

  RxDouble gpsLatitude = 0.0.obs;
  RxString gpsLatitudeDirection = "".obs;
  RxDouble gpsLongitude = 0.0.obs;
  RxString gpsLongitudeDirection = "".obs;
  RxDouble gpsAltitude = 0.0.obs;
  RxDouble gpsGeoidSeparation = 0.0.obs;
  RxInt gpsQuality = 0.obs;
  RxDouble gpsLatitudeError = 0.0.obs;
  RxDouble gpsLongitudeError = 0.0.obs;
  RxDouble gpsAltitudeError = 0.0.obs;
  Rx<DateTime> gpsDateTime = DateTime(2000).obs;
  Rx<Eov> eov = Eov(0, 0).obs;
  Rx<double?> eovHeight = 0.0.obs;

  RxInt latDegree = 0.obs;
  RxInt latMin = 0.obs;
  RxDouble latSec = 0.0.obs;
  RxInt longDegree = 0.obs;
  RxInt longMin = 0.obs;
  RxDouble longSec = 0.0.obs;

  RxDouble currentLongitude = 0.0.obs;
  RxDouble currentLatitude = 0.0.obs;
  RxDouble currentZoom = 12.0.obs;
  late final MapController mapController;
  final currentLocationMarker = <Marker>[];
  final pointNotesMarker = <Marker>[];

  List<PointToMeasure> pointsToMeasure = <PointToMeasure>[];
  final pointsToMeasureMarker = <Marker>[];
  final pointsToMeasureLabel = <PolyWidget>[];
  final pointsToMeasureDropDownMenuItem = <DropdownMenuItem<int>>[];
  RxInt pointsToMeasureSelectedValue = (-1).obs;
  RxDouble distance = 0.0.obs;

  late GeoidGrid geoidGrid;
  StreamSubscription<LocationData>? _phoneLocationSub;
  final _phoneLocation = Location();

  TextEditingController pointIdController = TextEditingController();
  TextEditingController pointDescriptionController = TextEditingController();
  TextEditingController gpsHeightController = TextEditingController();
  TextEditingController pointPrefixController = TextEditingController();
  TextEditingController pointPostfixController = TextEditingController();
  TextEditingController ntripUsernameController = TextEditingController();
  TextEditingController ntripPasswordController = TextEditingController();

  int pointId = 1;
  String pointIdPrefix = "";
  String pointIdPostfix = "";
  RxString ntripUserName = "".obs;
  RxString ntripPassword = "".obs;

  Rx<bool> pointMeasuringDirectionForward = true.obs;

  List<PointWithDescription> pointWithDescriptionList = [];
  late Directory? directory;
  late File dataFile;

  RxBool mapIsInitialized = false.obs;

  // GeoJsonParser parser =
  //     GeoJsonParser(defaultMarkerColor: const Color.fromARGB(255, 85, 34, 49));

  final CollectionReference _measuredPoints =
      FirebaseFirestore.instance.collection('measuredPoints');

  // late SMIBool gpsTrigger;
  // late StateMachineController riveGpsIconController;

  late SharedPreferences prefs;
  Rx<bool> isShowPassword = false.obs;
  final passwordFieldFocusNode = FocusNode();

  late AuthResponse authResponse;
  late Session? session;
  late User? user;

  @override
  void onInit() async {
    super.onInit();

    //Loading, Success, Error handle with 1 line of code
    nmeaDecoder
      ..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
      ..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
      ..registerTalkerSentence("GST", (line) => Gngst(raw: line));

    prefs = await SharedPreferences.getInstance();

    authResponse = await Supabase.instance.client.auth
        .signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
    session = authResponse.session;
    user = authResponse.user;

    Supabase.instance.client
        .channel('public:TerepiSeged_Receiver')
        .onPostgresChanges(
            event: PostgresChangeEvent.update,
            schema: 'public',
            table: 'TerepiSeged_Receiver',
            callback: (playload) {
              var id = playload.newRecord['pointNumber'] as int;
              print('Change received: ${id}');
              updatePointStatus(id);
            })
        .subscribe();

    geoidGrid = await GeoidGrid.load('assets/Grids/geoid_eht2014.gtx');

    mapController = MapController();

    // riveGpsIconController = RiveUtils.getRiveController(Artboard(),
    //     stateMachineName: "gps_Interactivity");
    // gpsTrigger = riveGpsIconController.findSMI("active");

    mapIsInitialized.value = true;
  }

  @override
  void onClose() async {
    super.onClose();
    FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
    if (gpsIsConnected.value) {
      connection.close();
      // connection = null;
      print("BluetoothTestController dispose ....");
    }

    _stopPhoneGps();

    pointDescriptionController.dispose();
    pointIdController.dispose();
    gpsHeightController.dispose();
    pointPrefixController.dispose();
    pointPostfixController.dispose();
    ntripUsernameController.dispose();
    ntripPasswordController.dispose();

    await Supabase.instance.client
        .channel('public:TerepiSeged_Receiver')
        .unsubscribe();
  }

  @override
  void onReady() async {
    super.onReady();

    _getInitialLocation();

    // String data = await rootBundle.loadString('assets/Files/transzekt.geojson');
    // parser.parseGeoJsonAsString(data);

    if (await permission_handler.Permission.storage.isGranted) {
      print("Storage permission is ok ...");
    } else {
      var result = await permission_handler.Permission.storage.request();
      if (result == permission_handler.PermissionStatus.granted) {
        print("Storage permission request is ok ....");
      } else {
        print("No storage permission");
      }
    }
    if (await permission_handler.Permission.manageExternalStorage.isGranted) {
      print("External storage permission is ok ...");
    } else {
      var result =
          await permission_handler.Permission.manageExternalStorage.request();
      if (result == permission_handler.PermissionStatus.granted) {
        print("External storage permission request is ok ....");
      } else {
        print("No external storage permission");
      }
      if (prefs.containsKey('gpsAddress')) {
        var address = prefs.getString('gpsAddress');
        if (address != null) {
          gpsAddress.value = address;
        }
      }
      if (prefs.containsKey('gpsName')) {
        var name = prefs.getString('gpsName');
        if (name != null) {
          gpsName.value = name;
        }
      }
      if (prefs.containsKey('ntripUserName')) {
        var userName = prefs.getString('ntripUserName');
        if (userName != null) {
          ntripUserName.value = userName;
        }
      }
      if (prefs.containsKey('ntripPassword')) {
        var password = prefs.getString('ntripPassword');
        if (password != null) {
          ntripPassword.value = password;
        }
      }
    }

    directory = await getExternalStorageDirectory();
    print(directory!.path);
    // String newPath = '';
    // List<String> folders = directory!.path.split("/");
    // for (int i = 1; i < folders.length; i++) {
    //   String folder = folders[i];
    //   if (folder != "Android") {
    //     newPath += "/" + folder;
    //   } else {
    //     break;
    //   }
    // }
    // newPath = newPath + "/TerepisSegedApp";
    // directory = Directory(newPath);
    if (!await directory!.exists()) {
      await directory!.create(recursive: true);
    }
    dataFile = File("${directory!.path}/data.txt");

    if (await directory!.exists()) {
      if (!await dataFile.exists()) {
        dataFile.writeAsString(
            "Id;DateTime;Description;EovX;EovY;Latitude;Longitude;Altitude;Hor.Err;Vert.Err\r\n");
      }
    }

    gpsHeightController.text = '1.8';
  }

  void _getInitialLocation() async {
    bool servicedEnabled;
    PermissionStatus permissionGranted;
    LocationData locationData;
    Location location = Location();

    servicedEnabled = await location.serviceEnabled();
    if (!servicedEnabled) {
      servicedEnabled = await location.requestService();
      if (!servicedEnabled) {
        return;
      }
    }

    permissionGranted = await location.hasPermission();
    if (permissionGranted == PermissionStatus.denied) {
      permissionGranted = await location.requestPermission();
      if (permissionGranted != PermissionStatus.granted) {
        return;
      }
    }

    locationData = await location.getLocation();
    currentLatitude.value = locationData.latitude ?? 0.0;
    currentLongitude.value = locationData.longitude ?? 0.0;
    print("Current location initialized -> $currentLatitude $currentLongitude");
    mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
        currentZoom.value);
    _updateCurrentLocationMarker();

    if (!gpsIsConnected.value) {
      await _startPhoneGps();
    }
  }

  Future<void> _startPhoneGps() async {
    if (_phoneLocationSub != null) return;

    // Frissítési beállítások — ezt a location csomag megköveteli
    await _phoneLocation.changeSettings(
      accuracy: LocationAccuracy.high,
      interval: 1000, // ms — másodpercenkénti frissítés
      distanceFilter: 0, // méter — minden frissítés jöjjön
    );

    // Engedély teljes körű ellenőrzése
    var permission = await _phoneLocation.hasPermission();
    if (permission == PermissionStatus.denied) {
      permission = await _phoneLocation.requestPermission();
    }
    if (permission != PermissionStatus.granted &&
        permission != PermissionStatus.grantedLimited) {
      return;
    }

    // GPS szolgáltatás ellenőrzése
    bool serviceEnabled = await _phoneLocation.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await _phoneLocation.requestService();
      if (!serviceEnabled) return;
    }

    print('Phone GPS: stream starting...');

    _phoneLocationSub = _phoneLocation.onLocationChanged.listen((data) {
      if (gpsIsConnected.value) {
        _stopPhoneGps();
        return;
      }
      if (data.latitude == null || data.longitude == null) return;

      currentLatitude.value = data.latitude!;
      currentLongitude.value = data.longitude!;
      _updateCurrentLocationMarker();
    });
  }

  void _stopPhoneGps() {
    _phoneLocationSub?.cancel();
    _phoneLocationSub = null;
  }

  void connectToGps() {
    if (gpsIsConnected == false) {
      BluetoothConnection.toAddress(gpsAddress.value).then((value) {
        connection = value;
        gpsIsConnected.value = true;
        print("GPS is connected ...");
        _stopPhoneGps();

        connection.input!.listen(_onDataReceived);
      });
    }
  }

  void disconnectFromGps() {
    if (gpsIsConnected.value) {
      connection.close();
      gpsIsConnected.value = false;
      _startPhoneGps();
      print("GPS is disconnected ....");
    }
    if (ntripIsConnected.value) {
      disconnectFromNtripServer();
    }
  }

  void connectToNtripServer() async {
    // socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
    //     timeout: const Duration(seconds: 5));
    socket = await Socket.connect(InternetAddress('84.206.45.44'), 2101,
        timeout: const Duration(seconds: 5));
    socket.asBroadcastStream;
    ntripIsConnected.value = true;

    socket.encoding = ascii;
    print("Connected to ntrip server ....");

    // String header = "GET /KOVARIK HTTP/1.1\r\n";
    String header = "GET /SGO_RTK3.2 HTTP/1.1\r\n";

    header += "User-Agent: SharpGps iter.dk\r\n";
    header += "Accept: */*\r\nConnection: close\r\n";
    // header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
    //header += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
    header +=
        "Authorization: Basic ${_toBase64("${ntripUserName.value}:${ntripPassword.value}")}\r\n";
    // header += "Host:rtk2go.com:2101\r\n";
    header += "Host:gnssnet.hu:2101\r\n";
    header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
    header += "\r\n";

    // listen for responses from the server
    socketStreamSubscription = socket.listen(
      // handle data from the server
      (Uint8List data) {
        // "ICY 200 OK" - first response
        final serverResponse = String.fromCharCodes(data);
        ntripReceivedData.value = data.length;
        ntripDataPacketNumbers.value++;
        if (gpsIsConnected.value) {
          if (data.length > 14) {
            connection.output.add(data);
          }
        }
        print('Server: $ntripReceivedData');
      },

      // handle errors
      onError: (error) {
        print(error);
        socket.destroy();
      },

      // handle server ending connection
      onDone: () async {
        print('Server left.');
        socketStreamSubscription.cancel();
        await socket.flush();
        ntripIsConnected.value = false;
        ntripReceivedData.value = 0;
        socket.destroy();
      },
    );

    socket.add(_convertStringToUint8List(header));

    // sendGgaMessage(lastGgaMessage);
  }

  void disconnectFromNtripServer() async {
    socketStreamSubscription.cancel();
    await socket.flush();
    socket.close();
    socket.destroy();
    ntripReceivedData.value = 0;
    ntripIsConnected.value = false;
    print("Disconnect from ntrip server....");
  }

  void _onDataReceived(Uint8List data) {
    String sentence = "";

    print("Bluetooth received -> ${data.length} byte(s)");
    String dataString = String.fromCharCodes(data);
    int index = data.indexOf(13);

    if (~index != 0) {
      sentence = _messageBuffer + dataString.substring(0, index);
      _messageBuffer = dataString.substring(index);
    } else {
      _messageBuffer = _messageBuffer + dataString;
    }

    // print("Message ($count): $sentence");
    _processGnssMessage(sentence);
  }

  String _toBase64(String str) {
    final bytes = ascii.encode(str);
    final base64Str = base64.encode(bytes);

    return base64Str;
  }

  Uint8List _convertStringToUint8List(String str) {
    final List<int> codeUnits = str.codeUnits;
    final Uint8List unit8List = Uint8List.fromList(codeUnits);
    return unit8List;
  }

  void _processGnssMessage(String message) {
    LineSplitter lineSplitter = const LineSplitter();
    List<String> lines = lineSplitter.convert(message);

    if (lines.isEmpty) {
      return;
    }

    for (String line in lines) {
      if (line.trim().isEmpty) {
        continue;
      }
      if (line.startsWith("\$GNGGA")) {
        final sentence = nmeaDecoder.decode(line);
        if (sentence!.valid && sentence is Gngga) {
          hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
          if (hasGpsValidData.value) {
            if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 0) {
              lastGpsRefreshTime = DateTime.now();
              utcOfPositionFix = sentence.utcOfPositionFix;
              gpsLatitude.value = sentence.latitude;
              gpsLatitudeDirection.value = sentence.latitudeDirection;
              gpsLongitude.value = sentence.longitude;
              gpsLongitudeDirection.value = sentence.longitudeDirection;
              gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
              gpsGeoidSeparation.value = sentence.geoidSeparation;
              gpsQuality.value = sentence.gpsQualityIndicator;
              eov.value = ConvertCoordinate.ConvertWgsToEov(
                  gpsLatitude.value, gpsLongitude.value);
              eovHeight.value = geoidGrid?.toEovHeight(
                  gpsLatitude.value,
                  gpsLongitude.value,
                  gpsAltitude.value,
                  gpsGeoidSeparation.value);

              if (pointsToMeasureSelectedValue.value >= 0) {
                double coordX =
                    pointsToMeasure[pointsToMeasureSelectedValue.value].coordX;
                double coordY =
                    pointsToMeasure[pointsToMeasureSelectedValue.value].coordY;
                var wgsCoord =
                    CoordConverterService.to.eovToWgsPoint(coordX, coordY);
                distance.value = calculateDistance(
                    LatLng(gpsLatitude.value, gpsLongitude.value),
                    LatLng(wgsCoord.y, wgsCoord.x));
              }
              latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
              latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
              latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
              longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
              longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
              longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
              currentLatitude.value = gpsLatitude.value;
              currentLongitude.value = gpsLongitude.value;
              _updateCurrentLocationMarker();
              lastGgaMessage = line;
              if (ntripIsConnected.value &&
                  (DateTime.now()
                          .difference(lastSendTimeGgaMessage)
                          .inSeconds >=
                      5)) {
                sendGgaMessage(lastGgaMessage);
                print("Send GGA message: $lastGgaMessage");
                ggaSenDataPacketNumber.value++;
                ggaSendLastTimeStr.value = utcOfPositionFix;
                lastSendTimeGgaMessage = DateTime.now();
              }
            }
          }
        }
      }
      if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
        final sentence = nmeaDecoder.decode(line);
        if (sentence!.valid && sentence is Gngst) {
          gpsLatitudeError.value = sentence.latitudeError;
          gpsLongitudeError.value = sentence.longitudeError;
          gpsAltitudeError.value = sentence.heightError;
        }
      }
      if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
        final sentence = nmeaDecoder.decode(line);
        if (sentence!.valid && sentence is Gnrmc) {
          utcDateOfPositionFix = sentence.date;
          if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
            gpsDateTime.value = DateTime(
                2000 +
                    int.parse(
                        "${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
                int.parse(
                    "${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
                int.parse(
                    "${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
                int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
                int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
                int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
          }
        }
      }
    }
  }

  String getGpsQualityIndicator({required int quality}) {
    String qualityStr = "Invalid";
    switch (quality) {
      case 0:
        {
          qualityStr = "Invalid";
        }
        break;
      case 1:
        {
          qualityStr = "Standard GPS (2D/3D)";
        }
        break;
      case 2:
        {
          qualityStr = "Differential GPS";
        }
        break;
      case 4:
        {
          qualityStr = "RTK Fix";
        }
        break;
      case 5:
        {
          qualityStr = "RTK Float";
        }
        break;
      case 6:
        {
          qualityStr = "Estimated (DR) Fix";
        }
        break;
      default:
        {
          qualityStr = "Invalid (-1)";
        }
    }
    return qualityStr;
  }

  void mapZoomOut() {
    double cLat, cLong;
    if (currentZoom.value > 0) {
      currentZoom.value = currentZoom.value - 1;
      cLat = isMapMoveToCenter.value
          ? currentLatitude.value
          : mapController.camera.center.latitude;
      cLong = isMapMoveToCenter.value
          ? currentLongitude.value
          : mapController.camera.center.longitude;
      mapController.move(LatLng(cLat, cLong), currentZoom.value);
    }
  }

  void mapZoomIn() {
    double cLat, cLong;
    if (currentZoom.value < maxZoomValue) {
      currentZoom.value++;
      cLat = isMapMoveToCenter.value
          ? currentLatitude.value
          : mapController.camera.center.latitude;
      cLong = isMapMoveToCenter.value
          ? currentLongitude.value
          : mapController.camera.center.longitude;
      mapController.move(LatLng(cLat, cLong), currentZoom.value);
    }
  }

  void _updateCurrentLocationMarker() {
    currentLocationMarker.clear();
    currentLocationMarker.add(Marker(
        point: LatLng(currentLatitude.value, currentLongitude.value),
        width: 15.0,
        height: 15.0,
        child: Container(
          width: 15.0,
          height: 15.0,
          decoration: BoxDecoration(
              color: getCurrentLocationMarkerColor(quality: gpsQuality.value),
              shape: BoxShape.circle,
              border: Border.all(width: 1.5, color: Colors.white)),
        )));
    if (isMapMoveToCenter.value) {
      mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
          currentZoom.value);
    }
  }

  Color getCurrentLocationMarkerColor({required int quality}) {
    Color qualityStr = Colors.black;
    switch (quality) {
      case 0:
        {
          qualityStr = Colors.black;
        }
        break;
      case 1:
        {
          qualityStr = Colors.red;
        }
        break;
      case 2:
        {
          qualityStr = Colors.blue;
        }
        break;
      case 4:
        {
          qualityStr = Colors.green;
        }
        break;
      case 5:
        {
          qualityStr = Colors.orange;
        }
        break;
      case 6:
        {
          qualityStr = Colors.yellow;
        }
        break;
      default:
        {
          qualityStr = Colors.white;
        }
    }
    return qualityStr;
  }

  void onBottomNavigationBarTap(int index) async {
    bool noMorePoint = false;
    print("OnBottomNavTap -> $index");
    if (index == 0) {
      pointIdController.text =
          '${pointsToMeasure[pointsToMeasureSelectedValue.value].id}';
      // pointIdController.text = pointId.toString();
      pointDescriptionController.text = "";
      Get.dialog(
        AlertDialog(
          title: const Text("Pont rögzítése"),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextField(
                controller: pointIdController,
                autofocus: true,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(), labelText: 'Azonosító'),
              ),
              const SizedBox(
                height: 20.0,
              ),
              TextField(
                controller: pointDescriptionController,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(), labelText: 'Leírás'),
              ),
              const SizedBox(
                height: 20,
              ),
              TextField(
                controller: gpsHeightController,
                autofocus: true,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(), labelText: 'GPS magasság'),
              ),
            ],
          ),
          actions: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                OutlinedButton(
                  style: OutlinedButton.styleFrom(
                      minimumSize: const Size(120.0, 40.0)),
                  child: const Text(
                    "Mégsem",
                    style: TextStyle(color: Colors.red),
                  ),
                  onPressed: () {
                    Get.back();
                  },
                ),
                OutlinedButton(
                  style: OutlinedButton.styleFrom(
                      minimumSize: const Size(120.0, 40.0)),
                  child: const Text(
                    "Ment",
                    style: TextStyle(
                        color: Colors.green, fontWeight: FontWeight.bold),
                  ),
                  onPressed: () async {
                    pointId = int.parse(pointIdController.text);
                    pointWithDescriptionList.add(PointWithDescription(
                        pointId,
                        gpsDateTime.value,
                        pointDescriptionController.text,
                        eov.value.Y,
                        eov.value.X,
                        gpsLatitude.value,
                        gpsLongitude.value,
                        max(gpsLatitudeError.value, gpsLongitudeError.value),
                        gpsAltitudeError.value));
                    print(
                        "pointWithDescriptionList -> ${pointWithDescriptionList.length}");

                    pointNotesMarker.add(Marker(
                        point: LatLng(gpsLatitude.value, gpsLongitude.value),
                        width: 15.0,
                        height: 15.0,
                        child: Container(
                          width: 15.0,
                          height: 15.0,
                          decoration: BoxDecoration(
                              color: Colors.amber[700],
                              shape: BoxShape.circle,
                              border:
                                  Border.all(width: 1.0, color: Colors.black)),
                        )));
                    await dataFile.writeAsString(
                        "$pointId;$gpsDateTime;${pointDescriptionController.text};${formatEovForFile.format(eov.value.Y)};${formatEovForFile.format(eov.value.X)};$gpsLatitude;$gpsLongitude;$gpsAltitude;${max(gpsLatitudeError.value, gpsLongitudeError.value)};$gpsAltitudeError;${gpsHeightController.text}\r\n",
                        mode: FileMode.append);

                    _measuredPoints.add({
                      "id": pointId,
                      "dateAndTime": gpsDateTime.value,
                      "latitude": gpsLatitude.value,
                      "longitude": gpsLongitude.value,
                      "altitude": gpsAltitude.value,
                      "eovY": formatEovForFile.format(eov.value.Y),
                      "eovX": formatEovForFile.format(eov.value.X),
                      "description": pointDescriptionController.text,
                      "horizontalError":
                          max(gpsLatitudeError.value, gpsLongitudeError.value),
                      "verticalError": gpsAltitudeError.value,
                      "gpsHeight": gpsHeightController.text
                    });

                    await Supabase.instance.client
                        .from('TerepiSeged_MeasuredPoints')
                        .insert({
                      'pointNumber': pointId,
                      'gnssNumber': gpsName.value,
                      'latitude': gpsLatitude.value,
                      'longitude': gpsLongitude.value,
                      'altitude': gpsAltitude.value,
                      'heightOfGeoid': gpsGeoidSeparation.value,
                      'eovX': eov.value.X,
                      'eovY': eov.value.Y,
                      'poleHeight': double.tryParse(gpsHeightController.text),
                      'horizontalError':
                          max(gpsLatitudeError.value, gpsLongitudeError.value),
                      'verticalError': gpsAltitudeError.value,
                      'description': pointDescriptionController.text,
                      'isDeleted': false,
                      'projectId': 2
                    });

                    await Supabase.instance.client
                        .from('TerepiSeged_Receiver')
                        .update({'isMeasured': true}).eq(
                            'pointNumber', pointId);

                    if (pointMeasuringDirectionForward.isTrue) {
                      if (pointsToMeasureSelectedValue.value <
                          pointsToMeasure.length - 1) {
                        pointId++;
                        pointsToMeasureSelectedValue.value += 1;
                        noMorePoint = false;
                      } else {
                        noMorePoint = true;
                        // Get.snackbar("Információ", "Nincs több bemérendő pont.",
                        //     colorText: Colors.white,
                        //     backgroundColor: Colors.lightBlue);
                        ScaffoldMessenger.of(Get.context!).showSnackBar(
                            const SnackBar(
                                content: Text('Nincs több bemérendő pont.')));
                      }
                    } else {
                      if (pointsToMeasureSelectedValue.value > 0) {
                        pointId--;
                        pointsToMeasureSelectedValue.value -= 1;
                        noMorePoint = false;
                      } else {
                        noMorePoint = true;
                        ScaffoldMessenger.of(Get.context!).showSnackBar(
                            const SnackBar(
                                content: Text('Nincs több bemérendő pont.')));
                      }
                    }

                    Get.back();
                  },
                ),
              ],
            )
          ],
        ),
        barrierDismissible: false,
      );
    }
  }

  void sendGgaMessage(String ggaMessage) {
    if (ntripIsConnected.value && ggaMessage.isNotEmpty) {
      socket.add(_convertStringToUint8List("$ggaMessage\r\n"));
    }
  }

  void setIsMapMoveToCenter() {
    isMapMoveToCenter.value = !isMapMoveToCenter.value;
    // onBottomNavigationBarTap(0);
  }

  void ReadPointsFromFile() async {
    File? file;
    FilePickerResult? result = await FilePicker.platform.pickFiles();

    if (result != null) {
      file = File(result.files.single.path!);
    } else {
      print("No file selected");
    }
    if (await file!.exists()) {
      pointsToMeasure.clear();
      final content = await file.readAsLines();
      print('Length: -> ${content.length}');

      for (final (index, item) in content.indexed) {
        if (index == 0) {
          continue;
        }
        var items = item.split(";");
        if (items.length >= 3) {
          var id = int.tryParse(items[0]);
          var coordX = double.tryParse(items[1].replaceAll(',', '.'));
          var coordY = double.tryParse(items[2].replaceAll(',', '.'));

          if (id != null && coordX != null && coordY != null) {
            pointsToMeasure
                .add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));

            var wgsCoord =
                CoordConverterService.to.eovToWgsPoint(coordX, coordY);

            print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");

            pointsToMeasureMarker.add(Marker(
                point: LatLng(wgsCoord.y, wgsCoord.x),
                width: 15.0,
                height: 15.0,
                child: Container(
                  width: 15.0,
                  height: 15.0,
                  decoration: BoxDecoration(
                      color: Colors.purple,
                      shape: BoxShape.circle,
                      border: Border.all(width: 1.0, color: Colors.black)),
                )));

            pointsToMeasureLabel.add(PolyWidget(
                center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
                widthInMeters: 3,
                heightInMeters: 3,
                // constraints: const BoxConstraints(
                //   minWidth: 250,
                //   maxWidth: 350,
                // ),
                child: FittedBox(
                  child: Padding(
                    padding: const EdgeInsets.all(4.0),
                    child: Text(
                      ' $id ',
                      style: const TextStyle(
                          fontWeight: FontWeight.bold,
                          color: Colors.yellow,
                          fontSize: 12.0),
                    ),
                  ),
                )));

            pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
              value: index - 1,
              child: Text('$id'),
            ));
          }
        }
      }
      pointsToMeasureSelectedValue.value = 0;
      print('Converted points number -> ${pointsToMeasure.length}');
    }
  }

  void readPointsFromSupa() async {
    // final AuthResponse res = await Supabase.instance.client.auth
    //     .signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
    // final Session? session = res.session;
    // final User? user = res.user;

    final data =
        await Supabase.instance.client.from('TerepiSeged_Receiver').select();
    print('supa count ->${data.length}');

    for (int i = 0; i < data.length; i++) {
      var items = data[i];
      if (items.length >= 3) {
        var id = items['pointNumber'];
        num numEovX = items['eovX'];
        var coordX = numEovX.toDouble();
        num numEovY = items['eovY'];
        var coordY = numEovY.toDouble();

        if (id != null && coordX != null && coordY != null) {
          pointsToMeasure
              .add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));

          var wgsCoord = CoordConverterService.to.eovToWgsPoint(coordX, coordY);

          print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");

          pointsToMeasureMarker.add(Marker(
              point: LatLng(wgsCoord.y, wgsCoord.x),
              width: 15.0,
              height: 15.0,
              child: Container(
                width: 15.0,
                height: 15.0,
                decoration: BoxDecoration(
                    color: Colors.purple,
                    shape: BoxShape.circle,
                    border: Border.all(width: 1.0, color: Colors.black)),
              )));

          pointsToMeasureLabel.add(PolyWidget(
              center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
              widthInMeters: 3,
              heightInMeters: 3,
              // constraints: const BoxConstraints(
              //   minWidth: 250,
              //   maxWidth: 350,
              // ),
              child: FittedBox(
                child: Padding(
                  padding: const EdgeInsets.all(4.0),
                  child: Text(
                    ' $id ',
                    style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        color: Colors.yellow,
                        fontSize: 12.0),
                  ),
                ),
              )));

          pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
            value: i,
            child: Text('$id'),
          ));
        }
      }
    }
    pointsToMeasureSelectedValue.value = 0;
    print('Converted points number -> ${pointsToMeasure.length}');
  }

  void pointsToMeasureSelectedValueChanged(int value) {
    pointsToMeasureSelectedValue.value = value;
    print('Selected point -> ${pointsToMeasureSelectedValue.value}');
  }

  double calculateDistance(LatLng start, LatLng end) {
    const double earthRadius = 6371.0; // Radius of the Earth in kilometers

    // Convert coordinates to radians
    final double lat1 = start.latitude * (pi / 180.0);
    final double lon1 = start.longitude * (pi / 180.0);
    final double lat2 = end.latitude * (pi / 180.0);
    final double lon2 = end.longitude * (pi / 180.0);

    // Calculate the differences between the coordinates
    final double dLat = lat2 - lat1;
    final double dLon = lon2 - lon1;

    // Apply the Haversine formula
    final double a = sin(dLat / 2) * sin(dLat / 2) +
        cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
    final double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    final double distance = earthRadius * c;

    return distance; // Distance in kilometers, add "*1000" to get meters
  }

  void addMeasuredPoint() {
    _measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
  }

  void showAddPointDialog() {
    onBottomNavigationBarTap(0);
  }

  void saveGpsAddress(String address) {
    prefs.setString('gpsAddress', address);
  }

  void saveGpsName(String name) {
    prefs.setString('gpsName', name);
  }

  void saveNtripUserName(String username) {
    prefs.setString('ntripUserName', username);
  }

  void saveNtripPassword(String password) {
    prefs.setString('ntripPassword', password);
  }

  void updatePointStatus(int pointId) {}

  void toggleShowPassword() {
    isShowPassword.value = !isShowPassword.value;
    if (passwordFieldFocusNode.hasPrimaryFocus) return;
    passwordFieldFocusNode.canRequestFocus = false;
  }

  void showMeasuredPointsTableDialog() {
    Get.to(() => MeasuredPointsTableDialog(), transition: Transition.fadeIn);
  }

  Future<List> readMeasuredPoints() async {
    var response = await Supabase.instance.client
        .from('TerepiSeged_MeasuredPoints')
        .select()
        .eq('projectId', 2)
        .order('created_at');

    print(response);

    return response;
  }

  void SaveMeasuredPointsToFile() async {
    // var pointsDirectory = await getExternalStorageDirectory();
    var pointsDirectory = await getApplicationDocumentsDirectory();
    print(directory!.path);
    // String newPath = '';
    // List<String> folders = directory!.path.split("/");
    // for (int i = 1; i < folders.length; i++) {
    //   String folder = folders[i];
    //   if (folder != "Android") {
    //     newPath += "/" + folder;
    //   } else {
    //     break;
    //   }
    // }
    // newPath = newPath + "/TerepisSegedApp";
    // directory = Directory(newPath);
    if (!await pointsDirectory!.exists()) {
      await pointsDirectory.create(recursive: true);
    }
    var oldMeasuredPointsFile = File("${directory!.path}/measuredsPoints.csv");

    if (await oldMeasuredPointsFile.exists()) {
      await oldMeasuredPointsFile.delete();
    }

    var measuredPointsFile =
        await File("${directory!.path}/measuredsPoints.csv").create();

    if (await pointsDirectory.exists()) {
      if (await measuredPointsFile.exists()) {
        await measuredPointsFile.writeAsString(
            "Id;DateTime;Description;EovX;EovY;Altitude;Hor.Err;Vert.Err\r\n");
      }
    }

    var data = await readMeasuredPoints();

    data.forEach((d) {
      measuredPointsFile.writeAsStringSync(
          "${d['id']};${d['created_at']};${d['description']};${formatEov.format(d['eovY'])};${formatEov.format(d['eovX'])};${formatEovZ.format(d['altitude'] - d['poleHeight'])};${formatAltitudeError.format(d['horizontalError'])};${formatAltitudeError.format(d['verticalError'])}\r\n",
          flush: true,
          mode: FileMode.append,
          encoding: utf8);
    });

    print('Number of data: ${data.length}');

    final params = ShareParams(
        text: "Mérési eredmények",
        // files: [XFile('$measuredPointsFile')],
        files: [XFile("${directory!.path}/measuredsPoints.csv")],
        subject: 'Mérési eredmények',
        title: 'Mérési eredmények');

    final result = await SharePlus.instance.share(params);
  }
}
