

import 'dart:convert';
import 'dart:io';

import 'package:camera_camera/camera_camera.dart';
import 'package:flutter/foundation.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/model/Rogaining.dart';
import 'package:rogapp/model/destination.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/action_service.dart';
import 'package:rogapp/services/destination_service.dart';
import 'package:rogapp/services/external_service.dart';
import 'package:rogapp/services/location_line_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/services/reacking_service.dart';
import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/widgets/bottom_sheet_new.dart';
import 'dart:async';

import 'package:rogapp/widgets/bottom_sheet_widget.dart';
import 'package:sqflite/sqlite_api.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';

class DestinationController extends GetxController {

  late LocationSettings locationSettings;

  var destinationCount = 0.obs;
  List<Destination> destinations = <Destination>[].obs;
  double current_lat = 0.0;
  double current_lon = 0.0;

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

  var is_in_checkin = false.obs;
  var is_in_rog = false.obs;
  var is_at_start = false.obs;
  var is_at_goal = false.obs;
  var is_photo_shoot = false.obs;
  //List<Rogaining> rogainings = <Rogaining>[].obs;

  bool checking_in = false;
  var is_gps_selected = true.obs;
  BuildContext? context;

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

  var travelMode = 0.obs;

  bool skip_gps = false;


  Map<String, dynamic> matrix = {};

  final photos = <File>[].obs;

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

  Timer? _timer;
  int _start = 0;
  int chekcs = 0;
  var rogaining_counted = 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"],
                                    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
                                  );
  }

  void startTimerLocation(GeoJsonFeature fs, double distance) {
    print("---- in startTimer ----");
    //skip_gps = true;
    double checkin_radious = fs.properties!['checkin_radius'] ?? double.infinity;
    if(checkin_radious >= distance){
      indexController.currentFeature.clear();
      Destination d = festuretoDestination(fs);
      for(Destination de in destinations){
        if(de.location_id == d.location_id){
          d = de;
          break;
        }
      }
      indexController.currentFeature.add(fs);
      print("---- before calling startTimer  ----");
      startTimer(d, distance);
    }
  }

  void startTimer(Destination d, double distance) async {
    skip_gps = true;
    print("---- in startTimer ----");
    double checkin_radious = d.checkin_radious ?? double.infinity;
    bool auto_checkin = d.auto_checkin == 0 ? false : true;
    bool location_already_checked_in = d.checkedin ?? false;
    bool isUser_logged_in = indexController.currentUser.length > 0 ? true : false;
    //make current destination
    print("---- checkin_radious ${checkin_radious} ----");
    print("---- distance ${distance} ----");
    if(checkin_radious >= distance){
      //currentSelectedDestinations.add(d);
      indexController.currentDestinationFeature.clear();
      indexController.currentDestinationFeature.add(d);

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

    if(is_photo_shoot.value == true){
      showModalBottomSheet(context: Get.context!, isScrollControlled: true,
          builder:((context) => CameraPage())
                ).whenComplete((){
                  skip_gps = false;
                  chekcs = 0;
                  is_in_checkin.value = false;
            });
      return;
    }

    DatabaseHelper db = DatabaseHelper.instance;
    List<Destination> ds = await db.getDestinationByLatLon(d.lat!, d.lon!);
    if(ds.isEmpty){
      print("----- in location popup  cp - ${d.cp}----");
      if(d.cp == -1){
        chekcs = 1;
        //start
              print("---- in start -----");
              chekcs = 1;
              is_in_checkin.value = true;
              is_at_start.value = true;
              showModalBottomSheet(context: Get.context!, isScrollControlled: true, 
                  builder:((context) => BottomSheetNew())
                ).whenComplete((){
                  skip_gps = false;
                  chekcs = 0;
                  is_at_start.value = false;
                  is_in_checkin.value = false;
                });
      }
      else if(is_in_rog.value == true && indexController.rog_mode == 1)
      {
        print("----- in location popup checkin   cp - ${d.cp}----");
        chekcs = 2;
        is_in_checkin.value = true;
        showModalBottomSheet(context: Get.context!, isScrollControlled: true,
          builder:((context) => BottomSheetNew())
        ).whenComplete((){
          skip_gps = false;
          chekcs =0;
          is_in_checkin.value = false;
        });
      }
    }

        print("---- location checkin radious ${d.checkin_radious} ----");          
        print("---- already checked in ${location_already_checked_in} ----");
          if(checkin_radious >= distance && location_already_checked_in == false && is_in_rog.value == true){
            if(auto_checkin){
              if(!checking_in){
                makeCheckin(d, true,"");
                if(d.cp != -1){
                  rogaining_counted.value =true;
                }
                skip_gps = false;
              }
            }
            else{
              print("--- hidden loc ${d.hidden_location} ----");
              // ask for checkin
              if(d.hidden_location != null && d.hidden_location == 0 && is_in_rog.value == true && d.cp != -1){
                // chekcs = 3;
                // is_in_checkin.value = true;
                // showModalBottomSheet(context: Get.context!, isScrollControlled: true,
                //   builder:((context) => CameraPage())
                // ).whenComplete((){
                //   skip_gps = false;
                //   chekcs = 0;
                //   is_in_checkin.value = false;
                // });
              }
              else if(is_in_rog.value == true && d.cp != -1){
                chekcs = 4;
                is_in_checkin.value = true;
                showMaterialModalBottomSheet(
                        expand: true,
                        context: Get.context!,
                        backgroundColor: Colors.transparent,
                        builder: (context) => BottomSheetNew()
                      ).whenComplete(() {
                          skip_gps = false;
                          chekcs = 0;
                          is_in_checkin.value = false;
                      });
                // showModalBottomSheet(context: Get.context!, isScrollControlled: true,
                //   builder:((context) => BottomSheetNew())
                // ).whenComplete((){
                //   skip_gps = false;
                //   chekcs = 0;
                //   is_in_checkin.value = false;
                // });
              }
              
            }
          }
          print("---- cp --- ${d.cp} -----");
          print("--- at goal ${is_at_goal} ---");
          print("--- rog counted ${rogaining_counted} ---");
          print("--- loc already checked in ${location_already_checked_in} ---");
          if(isUser_logged_in && d.cp == -1 && location_already_checked_in){
            //check for rogaining
            if(is_at_goal.value == false && rogaining_counted.value){
                //goal
                print("---- in goal -----");
                chekcs = 5;
                is_at_goal.value = true;
                showModalBottomSheet(context: Get.context!, isScrollControlled: true, 
                  builder:((context) => CameraPage())
                ).whenComplete((){
                  skip_gps = false;
                  chekcs = 0;
                  is_at_goal.value = false;
                });
            }
            else if(is_in_rog.value == false && indexController.rog_mode == 1){
              //start
              print("---- in start -----");
              chekcs = 6;
              is_at_start.value = true;
              showModalBottomSheet(context: Get.context!, isScrollControlled: true, 
                  builder:((context) => BottomSheetNew())
                ).whenComplete((){
                  print("----- finished start -------");
                  skip_gps = false;
                  chekcs = 0;
                  is_at_start.value = false;
                });
            }
          }
        print("---- _chekcs ${chekcs} ----");
        if(chekcs == 0){
          skip_gps = false;
        }
  }

  void resetRogaining(){
    currentSelectedDestinations.forEach((element) {
      deleteDestination(element);
    });

    is_in_checkin.value = false;
    is_in_rog.value = false;
    is_at_start.value = false;
    is_at_goal.value = false;
    

    _start = 0;
    chekcs = 0;
    rogaining_counted.value = false;
  }

  void openCamera(BuildContext context) {
    photos.clear();
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (_) => CameraCamera(
              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;
          }
        }
  }

  void checkForCheckin(double la, double ln){

    print("--- skip_gps ---- ${skip_gps}----");
    
    for(final d in destinations){

      print("--- check checkin for--loc_id- ${d.location_id}----");

        double lat = d.lat!;
        double lon = d.lon!;
        LatLng p = LatLng(lat, lon);
        getDestinationForLatLong(lat, lon).then((value){
          var distance = Distance();
          double dist = distance.as(LengthUnit.Meter, LatLng(lat, lon), LatLng(la, ln));
          //double checkin_radious = value!.checkin_radious ?? double.infinity;
          //bool auto_checkin = value.auto_checkin == 0 ? false : true;
          //bool location_already_checked_id = d.checkedin ?? false;

          // print("-----rogaining_counted---${rogaining_counted.value}-----");
          // print("-----is_in_rog---${is_in_rog}-----");
          // print("-----dist is ---${dist}-----");
          //print("----- ${indexController.currentUser} ----");

          if(dist <= 250 && skip_gps == false){
                //near a destination
            print("---- time with ${d.location_id} ----");
            startTimer(d, dist);
          }
          
        });

    }

    //check for location in bounds
    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 lat_fs = pt.latitude;
        double lon_fs = pt.longitude;
        LatLng p_fs = LatLng(lat_fs, lon_fs);
        var distance_fs = Distance();
        double dist_fs = distance_fs.as(LengthUnit.Meter, LatLng(lat_fs, lon_fs), LatLng(la, ln));

        if(dist_fs <= 250 && skip_gps == false){
          //near a location
          print("---- before call startTimerLocation  ----");
          startTimerLocation(fs, dist_fs);
        }
    }
  }

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

  void makeCheckin(Destination destination, bool action, String imageurl) async {
    //print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ressssss ${action}@@@@@@@@@@@");
      DatabaseHelper db = DatabaseHelper.instance;
      List<Destination> ddd = await db.getDestinationByLatLon(destination.lat!, destination.lon!);
  
      if(ddd.isEmpty){
        destination.checkedin = true;
        await db.insertDestination(destination);
      }

      PopulateDestinations();

      /// post to NATNAT
      if(indexController.currentUser.length > 0){
        double cp_num = destination.cp!;
        
        int user_id = indexController.currentUser[0]["user"]["id"];
        //print("--- Pressed -----");
        String _team = indexController.currentUser[0]["user"]['team_name'];
        //print("--- _team : ${_team}-----");
        String _event_code = 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 ${_event_code} ------");
        ExternalService().makeCheckpoint(user_id, _token, formattedDate, _team,cp_num.round(), _event_code, imageurl).then((value){
          print("------Ext service check point ${value} ------");
        });
      }

  }


  @override
  void onInit() async {

    checkPermission();
    PopulateDestinations();
    
    //print("------ in iniit");

    if (defaultTargetPlatform == TargetPlatform.android) {
      locationSettings = AndroidSettings(
        accuracy: LocationAccuracy.bestForNavigation,
        distanceFilter: 00,
        forceLocationManager: true,
        intervalDuration: const Duration(seconds: 10),
        //(Optional) Set foreground notification config to keep the app alive 
        //when going to the background
        foregroundNotificationConfig: const ForegroundNotificationConfig(
            notificationText:
            "Example app will continue to receive your location even when you aren't using it",
            notificationTitle: "Running in Background",
            enableWakeLock: true,
        )
      );
    } else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
      locationSettings = AppleSettings(
        accuracy: LocationAccuracy.bestForNavigation,
        activityType: ActivityType.fitness,
        distanceFilter: 30,
        pauseLocationUpdatesAutomatically: false,
        // Only set to true if our app will be started up in the background.
        showBackgroundLocationIndicator: true
      );
    } else {
        locationSettings = LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 30,
      );
    }

    try {

      StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(

      (Position? position) {
        current_lat = position != null ? position.latitude : 0;
        current_lon = position != null ? position.longitude : 0;

        if(is_gps_selected.value){
          double czoom = indexController.rogMapController!.zoom;
          indexController.rogMapController!.move(LatLng(position!.latitude, position!.longitude), czoom);
          //String user_id = indexController.currentUser[0]["user"]["id"].toString();
          //TrackingService.addTrack(user_id, position!.latitude, position.longitude).then((val){
            //print("---- postion is ${position.latitude},  ${position.longitude}");
            gps.clear();
            gps.add("-- lat : ${position.latitude}, lon : ${position.longitude} --");
            checkForCheckin(position!.latitude, position.longitude);
            print("--- call check checkin");
            print("---- skip gps is ${skip_gps.toString()} ----");
          //});
          
        }
          //print(position == null ? 'Unknown' : 'current position is ${position.latitude.toString()}, ${position.longitude.toString()}');
      });
    } catch (err){
      locationPermission.clear();
      locationPermission.add(err.toString());
    }

    ever(indexController.connectionStatusName, connectionChanged);

    super.onInit();

  }

  @override
  void onReady() {
    Get.toNamed(AppPages.LOGIN)!.then((value){
      if(indexController.currentUser.length > 0) {
        String _token = indexController.currentUser[0]["token"];
        indexController.switchPage(AppPages.INITIAL);
        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();
          }
        });
      }
      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 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 = new 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 = new 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 = null;
    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 deleteAllDestinations(){
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinations().then((value){
      PopulateDestinations();
    });
  }

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

  void addDestinations(Destination dest){

    print('------ destination controller in add destination ${dest.checkin_radious} ---- :::::');

    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;
    });
  }

  void PopulateDestinations(){
    print("--------- destination controller  populsting destinations ----------- ::::::");

    DatabaseHelper db = DatabaseHelper.instance;
    destinations.clear();
    db.getDestinations().then((value){
      destinationCount.value = 0;
      for(Destination d in value){
        print("------ destination controller populating destination-------- ${d.checkedin}-------- :::::");
        print("-----populated----- ${d.toMap()}");
        destinations.add(d);
      }
     // destinationCount.value = 0;
      print("------ destination controller destinationcount-------- ${destinationCount}-------- :::::");


      MatrixService.getDestinations(value).then((mat){
      print(" matrix is  -------  ${mat}");
      matrix = mat;

      try{
        getRoutePoints();
        destinationCount.value = destinations.length;
      }
      catch(_){
        skip_gps = false;
        return;
      }

    });
    });

  }
  

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


  void makeNext(Destination pt){

    for(int i=0; i<= destinations.length - 1; i++){
      Destination p = destinations[i];

      if(p.lat == pt.lat && p.lon == pt.lon ){
          
          if(indexController.currentDestinationFeature.isNotEmpty){
            indexController.currentDestinationFeature.clear();
          }
          if(i >= destinations.length - 1 ){
            indexController.currentDestinationFeature.add(destinations[0]);
            //getAction();
          }
          else{
            indexController.currentDestinationFeature.add(destinations[i + 1]);
            //getAction();
          }
      }
    }

  }

  void makePrevious(Destination pt){

    for(int i=0; i<= destinations.length - 1; i++){
      Destination p = destinations[i];

      if(p.lat == pt.lat && p.lon == pt.lon ){
          
          if(indexController.currentDestinationFeature.isNotEmpty){
            indexController.currentDestinationFeature.clear();
          }
          if(i <= 0){
            indexController.currentDestinationFeature.add(destinations[destinations.length -1]);
            //getAction();
          }
          else{
            indexController.currentDestinationFeature.add(destinations[i - 1]);
            //getAction();
          }
      }
    }

  }


}