import 'dart:io';
import 'package:camera_camera/camera_camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geojson/geojson.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:latlong2/latlong.dart';
import 'package:rogapp/main.dart';
import 'package:rogapp/model/destination.dart';
import 'package:rogapp/model/gps_data.dart';
import 'package:rogapp/pages/camera/camera_page.dart';
import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/routes/app_pages.dart';
import 'package:rogapp/services/destination_service.dart';
import 'package:rogapp/services/external_service.dart';
import 'package:rogapp/services/location_service.dart';
import 'package:rogapp/services/maxtrix_service.dart';
import 'package:rogapp/services/perfecture_service.dart';
import 'package:rogapp/utils/database_gps.dart';
import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/widgets/bottom_sheet_new.dart';
import 'dart:async';

import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:gallery_saver/gallery_saver.dart';

class DestinationController extends GetxController {
  late LocationSettings locationSettings;

  Timer? _GPStimer;

  var destinationCount = 0.obs;
  List<Destination> destinations = <Destination>[].obs;
  double currentLat = 0.0;
  double currentLon = 0.0;
  DateTime lastGPSCollectedTime = DateTime.now();

  static bool gps_push_started = false;
  static bool game_started = false;

  bool skip_10s = false;

  List<Destination> currentSelectedDestinations = <Destination>[].obs;

  var isInCheckin = false.obs;
  var isInRog = false.obs;
  var isAtStart = false.obs;
  var isAtGoal = false.obs;
  var isPhotoShoot = false.obs;
  DateTime lastGoalAt = DateTime.now().subtract(const Duration(days: 1));
  //List<Rogaining> rogainings = <Rogaining>[].obs;

  bool checkingIn = false;
  var isGpsSelected = true.obs;
  BuildContext? context;

  List<String> gps = <String>["-- stating --"].obs;
  List<String> locationPermission = <String>[" -- starting -- "].obs;

  var travelMode = 0.obs;

  bool skipGps = false;

  Map<String, dynamic> matrix = {};

  final photos = <File>[].obs;

  final IndexController indexController = Get.find<IndexController>();

  int _start = 0;
  int chekcs = 0;
  var rogainingCounted = false.obs;

  String getFormatedTime(DateTime datetime) {
    return DateFormat('yyyy-MM-dd HH:mm:ss').format(datetime);
  }

  Destination festuretoDestination(GeoJsonFeature fs) {
    GeoJsonMultiPoint mp = fs.geometry as GeoJsonMultiPoint;
    LatLng pt = LatLng(mp.geoSerie!.geoPoints[0].latitude,
        mp.geoSerie!.geoPoints[0].longitude);

    //print("----- ${indexController.currentFeature[0].properties} -----");

    return Destination(
        name: fs.properties!["location_name"],
        sub_loc_id: fs.properties!["sub_loc_id"],
        address: fs.properties!["address"],
        phone: fs.properties!["phone"],
        email: fs.properties!["email"],
        webcontents: fs.properties!["webcontents"],
        videos: fs.properties!["videos"],
        category: fs.properties!["category"],
        series: 1,
        lat: pt.latitude,
        lon: pt.longitude,
        location_id: fs.properties!["location_id"],
        list_order: 1,
        photos: fs.properties!["photos"],
        checkin_radious: fs.properties!["checkin_radius"],
        auto_checkin: fs.properties!["auto_checkin"] == true ? 1 : 0,
        cp: fs.properties!["cp"],
        checkin_point: fs.properties!["checkin_point"],
        buy_point: fs.properties!["buy_point"],
        selected: false,
        checkedin: false,
        hidden_location: fs.properties!["hidden_location"] == true ? 1 : 0,
        tags: fs.properties!["tags"]);
  }

  Future<void> startTimerLocation(GeoJsonFeature fs, double distance) async {
    //print("---- in startTimer ----");
    // print("---- is in rog is $is_in_rog ----");
    double checkinRadious = fs.properties!['checkin_radius'] ?? double.infinity;
    if (checkinRadious >= distance) {
      indexController.currentFeature.clear();
      Destination d = festuretoDestination(fs);
      // print("----- destination lenght is ${destinations.length} -----");
      indexController.currentFeature.add(fs);
      //print("---- before calling startTimer  ----");
      await startTimer(d, distance);
      return;
    }
  }

  Future<void> startTimer(Destination d, double distance) async {
    //print("=== passed dest  is ${d.location_id} ${d.checkedin} ====");
    skipGps = true;
    //print("---- in startTimer ----");

    DatabaseHelper db = DatabaseHelper.instance;
    List<Destination> ds = await db.getDestinationByLatLon(d.lat!, d.lon!);
    Destination? dss;
    if (ds.isNotEmpty) {
      dss = ds.first;
    }

    double checkinRadious = d.checkin_radious ?? double.infinity;
    bool autoCheckin = d.auto_checkin == 0 ? false : true;
    bool buyPoint = dss != null && dss.buy_point != null && dss.buy_point! > 0
        ? true
        : false;
    bool buyPointImageAdded =
        dss != null && dss.buypoint_image != null ? true : false;
    bool buyPointCanceled =
        dss != null && dss.buy_point != null && dss.buy_point == 0
            ? true
            : false;
    bool locationAlreadyCheckedIn =
        ds.isNotEmpty && ds[0].checkedin == true ? true : false;
    bool isuserLoggedIn = indexController.currentUser.isNotEmpty ? true : false;
    //make current destination
    // print("---- checkin_radious $checkinRadious ----");
    // print("---- distance $distance ----");
    if (checkinRadious >= distance) {
      //currentSelectedDestinations.add(d);
      indexController.currentDestinationFeature.clear();
      indexController.currentDestinationFeature.add(d);

      // print(
      //    "---- checked in as ${indexController.currentDestinationFeature[0].checkedin.toString()} ----");
    } else {
      skipGps = false;
      return;
    }

    if (isPhotoShoot.value == true) {
      photos.clear();
      await showModalBottomSheet(
          constraints: BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
          context: Get.context!,
          isScrollControlled: true,
          builder: ((context) => CameraPage(destination: d))).whenComplete(() {
        skipGps = false;
        chekcs = 0;
        isInCheckin.value = false;
      });
      return;
    }

    if (ds.isEmpty) {
      // print("----- in location popup  cp - ${d.cp}----");
      if (d.cp == -1 && DateTime.now().difference(lastGoalAt).inHours >= 24) {
        chekcs = 1;
        //start
        // print("~~~~ calling start ~~~~");
        // print("---- in start -----");
        chekcs = 1;
        isInCheckin.value = true;
        isAtStart.value = true;
        await showModalBottomSheet(
            constraints:
                BoxConstraints.loose(Size(Get.width, Get.height * 0.85)),
            context: Get.context!,
            isScrollControlled: true,
            builder: ((context) => BottomSheetNew(
                  destination: d,
                ))).whenComplete(() {
          skipGps = false;
          chekcs = 0;
          isAtStart.value = false;
          isInCheckin.value = false;
        });
        return;
      } else if (isInRog.value == true && indexController.rogMode.value == 1) {
        // print("----- in location popup checkin   cp - ${d.cp}----");
        chekcs = 2;
        isInCheckin.value = true;
        await showModalBottomSheet(
            constraints:
                BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
            context: Get.context!,
            isScrollControlled: true,
            builder: ((context) => BottomSheetNew(
                  destination: d,
                ))).whenComplete(() {
          skipGps = false;
          chekcs = 0;
          isInCheckin.value = false;
        });
        return;
      }
    }

    // print("---- location checkin radious ${d.checkin_radious} ----");
    // print("---- already checked in $locationAlreadyCheckedIn ----");
    if (checkinRadious >= distance &&
        locationAlreadyCheckedIn == false &&
        isInRog.value == true) {
      if (autoCheckin) {
        if (!checkingIn) {
          //print(
          //    "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@");
          makeCheckin(d, true, "");
          if (d.cp != -1) {
            rogainingCounted.value = true;
          }
          skipGps = false;
        }
        return;
      } else {
        // print("--- hidden loc ${d.hidden_location} ----");
        // ask for checkin
        if (d.hidden_location != null &&
            d.hidden_location == 0 &&
            isInRog.value == true &&
            d.cp != -1) {
          chekcs = 3;
          isInCheckin.value = true;
          photos.clear();
          // print("--- calling checkin ---");
          await showModalBottomSheet(
              constraints:
                  BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
              context: Get.context!,
              isScrollControlled: true,
              builder: ((context) => CameraPage(
                    destination: d,
                  ))).whenComplete(() {
            skipGps = false;
            rogainingCounted.value = true;
            chekcs = 0;
            isInCheckin.value = false;
          });
          return;
        } else if (isInRog.value == true && d.cp != -1) {
          chekcs = 4;
          isInCheckin.value = true;
          await showMaterialModalBottomSheet(
              expand: true,
              context: Get.context!,
              backgroundColor: Colors.transparent,
              builder: (context) => BottomSheetNew(
                    destination: d,
                  )).whenComplete(() {
            skipGps = false;
            chekcs = 0;
            isInCheckin.value = false;
          });
          return;
        }
      }
    } else if (checkinRadious >= distance &&
        locationAlreadyCheckedIn == true &&
        buyPointImageAdded == false &&
        ds.isNotEmpty &&
        buyPoint == true &&
        buyPointCanceled == false &&
        isInRog.value == true) {
      chekcs = 5;
      isInCheckin.value = true;
      photos.clear();
      //print("--- open buy point $buyPointImageAdded ${d.buypoint_image} ----");
      await showModalBottomSheet(
          constraints: BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
          context: Get.context!,
          isScrollControlled: true,
          builder: ((context) => CameraPage(
                buyPointPhoto: true,
                destination: d,
                dbDest: ds.first,
              ))).whenComplete(() {
        skipGps = false;
        rogainingCounted.value = true;
        chekcs = 0;
        isInCheckin.value = false;
      });
      return;
    }
    // print("---- cp --- ${d.cp} -----");
    // print("--- at goal $is_at_goal ---");
    // print("--- rog counted $rogaining_counted ---");
    // print("--- loc already checked in $locationAlreadyCheckedIn ---");
    // print(
    //     "==== date diff is  ${DateTime.now().difference(last_goal_at).inHours} ====");
    if (isuserLoggedIn &&
        d.cp == -1 &&
        locationAlreadyCheckedIn &&
        skip_10s == false) {
      //check for rogaining
      if (isAtGoal.value == false && rogainingCounted.value) {
        //goal
        //print("---- in goal -----");
        chekcs = 5;
        isAtGoal.value = true;
        photos.clear();
        await showModalBottomSheet(
            constraints:
                BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
            context: Get.context!,
            isScrollControlled: true,
            builder: ((context) => CameraPage(
                  destination: d,
                ))).whenComplete(() {
          skipGps = false;
          chekcs = 0;
          isAtGoal.value = false;
        });
        return;
      } else if (isInRog.value == false &&
          indexController.rogMode.value == 1 &&
          DateTime.now().difference(lastGoalAt).inHours >= 24) {
        //start
        //print("---- in start -----");
        chekcs = 6;
        isAtStart.value = true;
        await showModalBottomSheet(
            constraints:
                BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
            context: Get.context!,
            isScrollControlled: true,
            builder: ((context) => BottomSheetNew(
                  destination: d,
                ))).whenComplete(() {
          //print("----- finished start -------");
          skipGps = false;
          chekcs = 0;
          isAtStart.value = false;
        });
        return;
      }
    }
    //print("==== _chekcs $chekcs ====");
    if (chekcs == 0) {
      skipGps = false;
    }
    return;
  }

  Future<void> resetRogaining() async {
    //print("----- resetting --------");

    isInCheckin.value = false;
    isInRog.value = false;
    isAtStart.value = false;
    isAtGoal.value = false;
    isGpsSelected.value = true;
    skipGps = false;

    _start = 0;
    chekcs = 0;
    rogainingCounted.value = false;

    DatabaseHelper db = DatabaseHelper.instance;
    int? latgoal = await db.latestGoal();
    if (latgoal != null) {
      lastGoalAt = DateTime.fromMicrosecondsSinceEpoch(latgoal);
      //print("===== last goal : $last_goal_at =====");
    }
  }

  void deleteAllDestinations() {
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinations().then((value) {
      populateDestinations();
    });
  }

  void openCamera(BuildContext context, Destination? destination) {
    photos.clear();
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (_) => CameraCamera(
                  resolutionPreset: ResolutionPreset.medium,
                  onFile: (file) {
                    photos.add(file);
                    Navigator.pop(context);
                    //print("----image file is : $file----");
                    //setState(() {});
                  },
                )));
  }

  void getRoutePoints() {
    indexController.routePoints = [];
    indexController.routePointLenght.value = 0;
    DestinationService.getDestinationLine(destinations, matrix)?.then((value) {
      indexController.routePoints = value;
      indexController.routePointLenght.value =
          indexController.routePoints.length;
    });
  }

  Future<Destination?> getDestinationForLatLong(double lat, double long) async {
    for (final d in destinations) {
      if (lat == d.lat && long == d.lon) {
        return d;
      }
    }
    return null;
  }

  Future<void> callforCheckin(Destination d) async {
    bool autoCheckin = d.auto_checkin == 0 ? false : true;
    //print("---- f- checkin ${d.sub_loc_id} ----");
    if (autoCheckin) {
      if (!checkingIn) {
        makeCheckin(d, true, "");
        if (d.cp != -1) {
          rogainingCounted.value = true;
        }
      }
    } else {
      //print("--- hidden loc ${d.hidden_location} ----");
      // ask for checkin
      //print("is rog ---- ${is_in_rog.value} ----");
      if (d.hidden_location != null &&
          d.hidden_location == 0 &&
          isInRog.value == true &&
          d.cp != -1) {
        chekcs = 3;
        isInCheckin.value = true;
        photos.clear();
        await showModalBottomSheet(
            constraints:
                BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
            context: Get.context!,
            isScrollControlled: true,
            builder: ((context) => CameraPage(
                  manulaCheckin: true,
                  destination: d,
                ))).whenComplete(() async {
          if (d.buy_point != null && d.buy_point! > 0) {
            skipGps = true;
            photos.clear();
            DatabaseHelper db = DatabaseHelper.instance;
            List<Destination> ds =
                await db.getDestinationByLatLon(d.lat!, d.lon!);
            Destination? dss;
            if (ds.isNotEmpty) {
              dss = ds.first;
            }

            await showModalBottomSheet(
                constraints:
                    BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
                context: Get.context!,
                isScrollControlled: true,
                builder: ((context) => CameraPage(
                      buyPointPhoto: true,
                      destination: d,
                      dbDest: dss,
                    ))).whenComplete(() {
              skipGps = false;
              rogainingCounted.value = true;
              chekcs = 0;
              isInCheckin.value = false;
              Get.back();
            });
          } else {
            skipGps = false;
            chekcs = 0;
            isInCheckin.value = false;
          }
        });
      } else {
        Get.snackbar("始まっていない", "ロゲイニングを始める必要があります");
      }
    }
  }

  Future<void> addGPStoDB(double la, double ln, {isCheckin = 0}) async {
    GpsDatabaseHelper db = GpsDatabaseHelper.instance;
    final team_name = indexController.currentUser[0]["user"]['team_name'];
    final event_code = indexController.currentUser[0]["user"]["event_code"];
    GpsData gps_data = GpsData(
        id: 0,
        team_name: team_name,
        event_code: event_code,
        lat: la,
        lon: ln,
        is_checkin: isCheckin,
        created_at: DateTime.now().millisecondsSinceEpoch);
    var res = await db.insertGps(gps_data);
    //print("==gps res == ${res}");
  }

  Future<void> checkForCheckin() async {
    //print("--- Start of checkForCheckin function ---");
    game_started = true;

    try {
      //print("--- 000 ---- $skip_gps----");
      await Future.delayed(const Duration(milliseconds: 3000));
      Position position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.bestForNavigation);

      currentLat = position.latitude;
      currentLon = position.longitude;
      final la = position.latitude;
      final ln = position.longitude;

      //print("--- gps is ${la}, ${ln}");

      //add gps to database
      //check distance to previous point
      var distance = const Distance();
      double distanceToDest = distance.as(
          LengthUnit.Meter,
          LatLng(position.latitude, position.longitude),
          LatLng(currentLat, currentLon));
      Duration difference =
          lastGPSCollectedTime.difference(DateTime.now()).abs();
      if (difference.inSeconds >= 10 || distanceToDest >= 10) {
        print(
            "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}");

        await addGPStoDB(la, ln);
        lastGPSCollectedTime = DateTime.now();
      }

      // GpsDatabaseHelper db = GpsDatabaseHelper.instance;
      // final team_name = indexController.currentUser[0]["user"]['team_name'];
      // final event_code = indexController.currentUser[0]["user"]["event_code"];
      // print("--- curr gps is ${la}, ${ln}");
      // GpsData gps_data = GpsData(
      //     id: 0,
      //     team_name: team_name,
      //     event_code: event_code,
      //     lat: la,
      //     lon: ln,
      //     created_at: DateTime.now().microsecondsSinceEpoch);
      // await db.insertGps(gps_data);

      for (GeoJsonFeature fs in indexController.locations[0].collection) {
        GeoJsonMultiPoint mp = fs.geometry as GeoJsonMultiPoint;
        LatLng pt = LatLng(mp.geoSerie!.geoPoints[0].latitude,
            mp.geoSerie!.geoPoints[0].longitude);

        double latFs = pt.latitude;
        double lonFs = pt.longitude;
        var distanceFs = const Distance();
        //print("--- points : ${pt.latitude}, ${pt.longitude} ----");
        //print("--- points : ${pt.latitude}, ${pt.longitude} ----");
        double distFs = distanceFs.as(
            LengthUnit.Meter, LatLng(latFs, lonFs), LatLng(la, ln));
        Destination des = festuretoDestination(fs);

        //print(
        //   "--- position is ---- ${position.longitude}, --- ${position.longitude}----");

        //print("--- distFs ---- $distFs, --- ${des.checkin_radious}----");
        if (distFs <= des.checkin_radious! && skipGps == false) {
          //print("--- 789 ---- $skip_gps----");
          //near a location
          //print("---- before call startTimerLocation  ----");
          await startTimerLocation(fs, distFs);
          break;
        }
      }
      if (gps_push_started == false) {
        pushGPStoServer();
      }
      //print("--- 123 ---- $skip_gps----");
    } catch (e) {
      //print("An error occurred: $e");
      await checkForCheckin();
    } finally {
      //print("--- End of checkForCheckin function, calling recursively ---");
      await checkForCheckin();
    }
  }

  Future<void> pushGPStoServer() async {
    // print(
    //     "^^^^^^^^ ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}");
    try {
      gps_push_started = true;
      ExternalService().pushGPS();
    } catch (e) {
      //print("An error occurred: $e");
      //await pushGPStoServer();
    } finally {
      //print("--- End of pushGPStoServer function, calling recursively ---");
      await Future.delayed(const Duration(seconds: 5 * 60));
      await pushGPStoServer();
    }
  }

  void addToRogaining(double lat, double lon, int destinationId) async {
    DatabaseHelper db = DatabaseHelper.instance;
    List<Destination> d = await db.getDestinationById(destinationId);
    if (d.isEmpty) {
      Destination df = festuretoDestination(indexController.currentFeature[0]);
      //print("--- made checkin ${df.location_id} ----");
      makeCheckin(df, true, "");
    }
    isInRog.value = true;

    saveGameState();
  }

  Future<void> cancelBuyPoint(Destination destination) async {
    DatabaseHelper db = DatabaseHelper.instance;
    await db.updateCancelBuyPoint(destination);
    populateDestinations();
  }

  Future<void> makeBuyPoint(Destination destination, String imageurl) async {
    DatabaseHelper db = DatabaseHelper.instance;
    await db.updateBuyPoint(destination, imageurl);
    populateDestinations();
    await GallerySaver.saveImage(imageurl);

    if (indexController.currentUser.isNotEmpty) {
      double cpNum = destination.cp!;

      int userId = indexController.currentUser[0]["user"]["id"];
      //print("--- Pressed -----");
      String team = indexController.currentUser[0]["user"]['team_name'];
      //print("--- _team : ${_team}-----");
      String eventCode = indexController.currentUser[0]["user"]["event_code"];
      //print("--- _event_code : ${_event_code}-----");
      String token = indexController.currentUser[0]["token"];
      //print("--- _token : ${_token}-----");
      DateTime now = DateTime.now();
      String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(now);

      //print("------ checkin event $eventCode ------");
      ExternalService()
          .makeCheckpoint(userId, token, formattedDate, team, cpNum.round(),
              eventCode, imageurl)
          .then((value) {
        //print("------Ext service check point $value ------");
      });
    }
  }

  Future<void> makeCheckin(
      Destination destination, bool action, String imageurl) async {
    // print("~~~~ calling checkin function ~~~~");
    // print(
    //    "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ressssss ${destination.sub_loc_id}@@@@@@@@@@@");
    DatabaseHelper db = DatabaseHelper.instance;
    List<Destination> ddd =
        await db.getDestinationByLatLon(destination.lat!, destination.lon!);

    if (ddd.isEmpty) {
      destination.checkedin = true;
      destination.checkin_image = imageurl;
      await db.insertDestination(destination);
      // print("~~~~ inserted into db ~~~~");
    }

    await GallerySaver.saveImage(imageurl);

    populateDestinations();

    /// post to NATNAT
    if (indexController.currentUser.isNotEmpty) {
      double cpNum = destination.cp!;

      int userId = indexController.currentUser[0]["user"]["id"];
      //print("--- Pressed -----");
      String team = indexController.currentUser[0]["user"]['team_name'];
      //print("--- _team : ${_team}-----");
      String eventCode = indexController.currentUser[0]["user"]["event_code"];
      //print("--- _event_code : ${_event_code}-----");
      String token = indexController.currentUser[0]["token"];
      //print("--- _token : ${_token}-----");
      DateTime now = DateTime.now();
      String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(now);

      await addGPStoDB(currentLat, currentLon, isCheckin: 1);

      // print("------ checkin event $eventCode ------");
      ExternalService()
          .makeCheckpoint(userId, token, formattedDate, team, cpNum.round(),
              eventCode, imageurl)
          .then((value) {
        // print("------Ext service check point $value ------");
      });
    }
  }

  Future<void> removeCheckin(int cp) {
    return ExternalService().removeCheckin(cp);
  }

  Future<void> startGame() async {
    //print("------ starting game ------");
    if (game_started == false) {
      await checkForCheckin();
    }
  }

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

  double distanceToStart() {
    //print("=== gfs len == ${indexController.locations[0].collection.length}");
    GeoJsonFeature gfs = indexController.locations[0].collection
        .firstWhere((element) => festuretoDestination(element).cp == -1);

    Destination des = festuretoDestination(gfs);

    //print("=== gfs == ${des.toMap()}");

    double distanceToDest = double.infinity;
    var distance = const Distance();
    distanceToDest = distance.as(LengthUnit.Meter,
        LatLng(currentLat, currentLon), LatLng(des.lat!, des.lon!));
    //print("==== dist==${distanceToDest}");
    return distanceToDest;
  }

  int getForcedChckinDistance(Destination dest) {
    int _retValue = 100;
    if (dest.cp == -1) {
      return 500;
    }
    Destination? ds;
    GeoJsonFeature gfs = indexController.locations[0].collection
        .firstWhere((element) => festuretoDestination(element).cp == -1);

    ds = festuretoDestination(gfs);
    var distance = const Distance();
    double distanceToDest = distance.as(LengthUnit.Meter,
        LatLng(dest.lat!, dest.lon!), LatLng(ds.lat!, ds.lon!));
    if (distanceToDest <= 500) {
      return 500;
    }
    //print("====  forced dist ==${distanceToDest}");
    return _retValue;
  }

  readUserToken() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    indexController.userToken = prefs.getString("user_token");
  }

  @override
  void onReady() async {
    await readUserToken();
    final token = indexController.userToken;
    if (token != null && token.isNotEmpty) {
      await indexController.loadUserDetailsForToken(token);
      fixMapBound(token);
      return;
    }

    Get.toNamed(AppPages.LOGIN)!.then((value) {
      if (indexController.currentUser.isNotEmpty) {
        final tk = indexController.currentUser[0]["token"];
        fixMapBound(tk);
      } else {
        Get.toNamed(AppPages.TRAVEL);
        PerfectureService.getSubExt("9").then((value) {
          if (value != null) {
            LatLngBounds bnds = LatLngBounds(
                LatLng(value[1], value[0]), LatLng(value[3], value[2]));
            indexController.mapController
                .fitBounds(bnds); //.centerZoomFitBounds(bnds);
          }
        });
      }
    });
    super.onReady();
  }

  void fixMapBound(String token) {
    //String _token = indexController.currentUser[0]["token"];
    indexController.switchPage(AppPages.INDEX);
    LocationService.getLocationsExt(token).then((value) {
      if (value != null) {
        //print("--- loc ext is - $value ----");
        LatLngBounds bnds = LatLngBounds(
            LatLng(value[1], value[0]), LatLng(value[3], value[2]));
        //print("--- bnds is - $bnds ----");
        indexController.mapController.fitBounds(
          bnds,
        );
        indexController.currentBound.clear();
        indexController.currentBound.add(bnds);
        indexController.loadLocationsBound();
      }
    });
  }

  void connectionChanged(String val) {
    //print('----- %%%%%%%%%%%%%%%%%%%%% ----- $val');
    Map<String, dynamic> res = {};
    if (val == "wifi" || val == "mobile") {
      String token = indexController.currentUser[0]["token"];
      DatabaseHelper db = DatabaseHelper.instance;
      db.allRogianing().then((value) {
        value.forEach((e) async {
          if (e.rog_action_type == 0) {
            res = await ExternalService().startRogaining();
          } else if (e.rog_action_type == 1) {
            var datetime = DateTime.fromMicrosecondsSinceEpoch(e.checkintime!);
            res = await ExternalService().makeCheckpoint(
                e.user_id!,
                token,
                getFormatedTime(datetime),
                e.team_name!,
                e.cp_number!,
                e.event_code!,
                e.image!);
          } else if (e.rog_action_type == 2) {
            var datetime = DateTime.fromMicrosecondsSinceEpoch(e.checkintime!);
            res = await ExternalService().makeGoal(
                e.user_id!,
                token,
                e.team_name!,
                e.image!,
                getFormatedTime(datetime),
                e.event_code!);
          }

          if (res.isNotEmpty) {
            db.deleteRogaining(e.id!);
          }
        });
      });
    }
  }

  void checkPermission() async {
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission != LocationPermission.whileInUse ||
        permission != LocationPermission.always) {
      locationPermission.clear();
      locationPermission.add(permission.name);
      permission = await Geolocator.requestPermission();
    }
  }

  Destination? destinationById(int id) {
    Destination? d;
    //print("--- target des - $id ----");
    for (Destination ss in destinations) {
      //print("--- des - ${ss.location_id} ----");
      if (ss.location_id == id) {
        d = ss;
        break;
      }
    }
    return d;
  }

  void deleteDestination(Destination d) {
    //int id = destinations[index].location_id!;
    //print("---- index ${destinations[index].location_id!}-----");
    for (Destination ss in destinations) {
      if (ss.location_id == d.location_id) {
        destinations.remove(ss);
        break;
      }
    }
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteDestination(d.location_id!).then((value) {
      populateDestinations();
    });
  }

  void deleteDBDestinations() {
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinations().then((value) {
      populateDestinations();
    });
  }

  // ---------- database ------------------///

  void addDestinations(Destination dest) {
    DatabaseHelper db = DatabaseHelper.instance;
    db.getDestinationByLatLon(dest.lat!, dest.lon!).then((value) {
      if (value.isNotEmpty) {
        db.deleteDestination(value[0].location_id!).then((value) {
          db.insertDestination(dest).then((value) {
            //print(
            //    "----- destination controller   deleted and inserted destination id $value ---- :::::");
            populateDestinations();
          });
        });
      } else {
        db.insertDestination(dest).then((value) {
          //print("----- destination controller  added as new $value--- :::::");
          populateDestinations();
        });
      }
    });
  }

  void toggleSelection(Destination dest) async {
    DatabaseHelper db = DatabaseHelper.instance;
    await db.toggleSelecttion(dest);
    destinations.clear();
    db.getDestinations().then((value) {
      destinationCount.value = 0;
      currentSelectedDestinations.clear();
      for (Destination d in value) {
        //print("------ destination controller populating destination-------- ${d.checkedin}-------- :::::");
        //print("-----populated----- ${d.toMap()}");
        if (d.selected!) {
          currentSelectedDestinations.add(d);
        }
        destinations.add(d);
      }
      destinationCount.value = destinations.length;
    });
  }

  buildShowDialog(BuildContext context) {
    return showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        });
  }

  void destinationMatrixFromCurrentPoint(List<Destination> points) {
    buildShowDialog(Get.context!);
    MatrixService.getDestinations(points).then((mat) {
      //print(" matrix is  -------  $mat");
      matrix = mat;

      try {
        indexController.routePoints = [];
        indexController.routePointLenght.value = 0;
        DestinationService.getDestinationLine(points, matrix)?.then((value) {
          indexController.routePoints = value;
          indexController.routePointLenght.value =
              indexController.routePoints.length;
          //Get.toNamed(AppPages.TRAVEL);
        });
        destinationCount.value = destinations.length;
      } catch (_) {
        skipGps = false;
        return;
      } finally {
        Get.back();
      }
    });
  }

  void populateDestinations() {
    DatabaseHelper db = DatabaseHelper.instance;
    destinations.clear();
    db.getDestinations().then((value) {
      destinationCount.value = 0;
      for (Destination d in value) {
        destinations.add(d);
      }
      if (destinations.isEmpty) {
        rogainingCounted.value = false;
      }
    });
  }

  void makeOrder(Destination d, int dir) {
    DatabaseHelper db = DatabaseHelper.instance;
    db.updateOrder(d, dir).then((value) {
      populateDestinations();
    });
  }
}
