import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:geojson/geojson.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:rogapp/model/destination.dart';
import 'package:rogapp/pages/destination/destination_binding.dart';
import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/destination/destination_page.dart';
import 'package:rogapp/routes/app_pages.dart';
import 'package:rogapp/services/action_service.dart';
import 'package:rogapp/services/auth_service.dart';
import 'package:rogapp/services/cat_service.dart';
import 'package:rogapp/services/location_service.dart';
import 'package:rogapp/services/perfecture_service.dart';
import 'package:rogapp/utils/database_helper.dart';

class IndexController extends GetxController {
  List<GeoJsonFeatureCollection> locations = <GeoJsonFeatureCollection>[].obs;
  List<GeoJsonFeature> currentFeature = <GeoJsonFeature>[].obs;
  List<Destination> currentDestinationFeature = <Destination>[].obs;
  List<dynamic> perfectures = <dynamic>[].obs;
  List<LatLngBounds> currentBound = <LatLngBounds>[].obs;
  List<dynamic> subPerfs = <dynamic>[].obs;
  List<dynamic> areas = <dynamic>[].obs;
  List<dynamic> customAreas = <dynamic>[].obs;
  List<dynamic> cats = <dynamic>[].obs;

  List<String> currentCat = <String>[].obs;

  List<Map<String, dynamic>> currentUser = <Map<String, dynamic>>[].obs;
  List<dynamic> currentAction = <dynamic>[].obs;
  List<PointLatLng> routePoints = <PointLatLng>[].obs;
  var routePointLenght = 0.obs;

  var is_loading = false.obs;

  var is_mapController_loaded = false.obs;
  var is_rog_mapcontroller_loaded = false.obs;

  var is_custom_area_selected = false.obs;

  MapController? mapController;
  MapController? rogMapController;

  var mode = 0.obs;

  // master mode, rog or selection
  var rog_mode = 1.obs;

  var desination_mode = 1.obs;

  bool showPopup = true;


  String dropdownValue = "9"; 
  String subDropdownValue = "-1";
  String areaDropdownValue = "-1";
  String cateogory = "-all-";

  late Worker _ever;

  ConnectivityResult connectionStatus = ConnectivityResult.none;
  var connectionStatusName = "".obs;
  final Connectivity _connectivity = Connectivity();
  late StreamSubscription<ConnectivityResult> _connectivitySubscription;

  void toggleMode(){
    if(mode.value==0){
      mode += 1;
    }
    else{
      mode -= 1;
    }
  }

  void toggleDestinationMode(){
    if(desination_mode.value==0){
      desination_mode.value += 1;
    }
    else{
      desination_mode.value -= 1;
    }
  }

  void switchPage(String page){
    //print("######## ${currentUser[0]["user"]["id"]}");
    switch (page) {
      case AppPages.INITIAL :{
        rog_mode.value = 0;
        print("-- rog mode is ctrl is ${rog_mode.value}");
        Get.toNamed(page);
      }
        break;
      case AppPages.TRAVEL : {
        rog_mode.value = 1;
        //Get.back();
        Get.off(DestnationPage(), binding: DestinationBinding());

      }
      break;
      case AppPages.LOGIN :{
        rog_mode.value = 2;
        Get.toNamed(page);
      }
      break;
      default:{
        rog_mode.value = 0;
        Get.toNamed(AppPages.INITIAL);
      }
    }
  }

  @override
  void onInit() {
    _ever = ever(rog_mode, (_) => print("$_ has been changed (ever)"));

    if(perfectures.length == 0){
      PerfectureService.loadPerfectures().then((value){
        perfectures.add(value);
        loadAreaFor("9");
        
        //loadSubPerfFor("9");
      });
    } 

    _connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);

    super.onInit();
}

@override
void onClose() {
    _connectivitySubscription.cancel();
    super.onClose();
}

Future<void> _updateConnectionStatus(ConnectivityResult result) async {
      connectionStatus = result;
      connectionStatusName.value = result.name;
}

Future<void> initConnectivity() async {
    late ConnectivityResult result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      result = await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print('Couldn\'t check connectivity status --- $e');
      return;
    }

    return _updateConnectionStatus(result);
  }

LatLngBounds boundsFromLatLngList(List<LatLng> list) {
  double? x0, x1, y0, y1;
  for (LatLng latLng in list) {
    if (x0 == null || x1 == null || y0 == null || y1 == null) {
      x0 = x1 = latLng.latitude;
      y0 = y1 = latLng.longitude;
    } else {
      if (latLng.latitude > x1) x1 = latLng.latitude;
      if (latLng.latitude < x0) x0 = latLng.latitude;
      if (latLng.longitude > y1) y1 = latLng.longitude;
      if (latLng.longitude < y0) y0 = latLng.longitude;
    }
  }

  return LatLngBounds(LatLng(x1!, y1!), LatLng(x0!, y0!));
}


List<LatLng> getLocationsList(){
  List<LatLng> locs = [];
  for(int i=0; i<= locations[0].collection.length - 1; i++){
    GeoJsonMultiPoint p = locations[0].collection[i].geometry as GeoJsonMultiPoint;

    LatLng latLng = LatLng(p.geoSerie!.geoPoints[0].latitude, p.geoSerie!.geoPoints[0].longitude);
    locs.add(latLng);  
  }
  return locs;
}


void login(String email, String password, BuildContext context){
     AuthService.login(email, password).then((value){
      print("------- logged in user details ######## ${value} ###### --------");
       if(value.isNotEmpty){
          currentUser.clear();
          currentUser.add(value);
          is_loading.value = false;
          Navigator.pop(context);
          loadUserDetails();
          loadLocationsBound();
          cats.clear();
          if(currentFeature.isNotEmpty){
            getAction();
          }

          if(currentUser.length > 0){
            rog_mode.value = 0  ;
          }
          else{
            rog_mode.value = 1;
          }

          if(rog_mode.value == 1){
            switchPage(AppPages.TRAVEL);
          }
          else{
            switchPage(AppPages.INITIAL);
          }
          //Get.toNamed(AppPages.INITIAL);
       }else{
        is_loading.value = false;
        Get.snackbar(
              "Failed",
               "User login failed, please try again.",
               icon: Icon(Icons.error, size: 40.0, color: Colors.blue),
               snackPosition: SnackPosition.TOP,
               duration: Duration(milliseconds: 800),
               backgroundColor: Colors.yellow,
               //icon:Image(image:AssetImage("assets/images/dora.png"))
               );
       }
       
     });
   }

   void changePassword(String oldpassword, String newpassword, BuildContext context){
      String _token = currentUser[0]['token'];
      //print("------- change password ######## ${currentUser[0]['token']} ###### --------");
      AuthService.changePassword(oldpassword, newpassword, _token).then((value){
      print("------- change password ######## ${value} ###### --------");
       if(value.isNotEmpty){
        is_loading.value = false;
        Navigator.pop(context);
        if(rog_mode.value == 1){
          switchPage(AppPages.TRAVEL);
        }
        else{
          switchPage(AppPages.INITIAL);
        }
       }else{
        Get.snackbar(
              'failed'.tr,
               'password_change_failed_please_try_again'.tr,
               icon: Icon(Icons.error, size: 40.0, color: Colors.blue),
               snackPosition: SnackPosition.TOP,
               duration: Duration(milliseconds: 800),
               backgroundColor: Colors.yellow,
               //icon:Image(image:AssetImage("assets/images/dora.png"))
               );
       }
       
     });
     is_loading.value = false;
   }

   void logout() async{
    locations.clear();
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinations().then((value){
      DestinationController destinationController = Get.find<DestinationController>();
      if(destinationController != null){
        destinationController.PopulateDestinations();
      }
    });
    currentUser.clear();
    cats.clear();
   }

   void register(String email, String password, BuildContext context){
     AuthService.register(email, password).then((value){
       if(value.isNotEmpty){
        currentUser.clear();
        currentUser.add(value);
        is_loading.value = false;
        Navigator.pop(context);
        loadUserDetails();
        Get.toNamed(AppPages.INITIAL);
       }else{
         is_loading.value = false;
         Get.snackbar(
              'failed'.tr,
              'user_registration_failed_please_try_again'.tr,
               icon: Icon(Icons.error, size: 40.0, color: Colors.blue),
               snackPosition: SnackPosition.TOP,
               duration: Duration(milliseconds: 800),
               backgroundColor: Colors.yellow,
               //icon:Image(image:AssetImage("assets/images/dora.png"))
               );
       }
     });
   }

   void makeAction(BuildContext context){
    int user_id = currentUser[0]["user"]["id"] as int;
    int location_id = currentFeature[0].properties!["location_id"] as int;
     bool wanttogo = currentAction[0][0]["wanttogo"];
     bool like = currentAction[0][0]["like"];
     bool checkin = currentAction[0][0]["checkin"];
     if(user_id > 0){
       ActionService.makeAction(user_id, location_id, wanttogo, like, checkin).then((value){
       });
     }
     
   }

  String getCatText(){
    String _cat = 'all'.tr;
    if(currentUser.length > 0){
      Map<String, dynamic> _urs = currentUser[0];
      print('-- is_rogaining :-- ${_urs['user']['is_rogaining']} ------');
      if(_urs['user']['is_rogaining'] == true){
        _cat = 'rogaining'.tr;
      }
      else {
        _cat = 'sight_seeing'.tr;
      }
    }
    return _cat;
  }

  void loadCatsv2(){
     dynamic initVal = {'category':getCatText()};
     LatLngBounds bounds = mapController!.bounds!;
     if(bounds.southEast != null && bounds.southWest != null && bounds.northEast != null && bounds.southEast != null ){
       CatService.loadCats(bounds.southWest!.latitude, bounds.southWest!.longitude, bounds.northWest.latitude, bounds.northWest.longitude, bounds.northEast!.latitude, bounds.northEast!.longitude, bounds.southEast.latitude, bounds.southEast.longitude).then((value) {
          cats.clear();
          cats.add(initVal);
          for(dynamic cat in value!){
            if(cat['category'] != null){
              cats.add(cat!);
            }
          }
       });
     }
   }

   void loadCatForCity(String city){
    dynamic initVal = {'category':getCatText()};
     LatLngBounds bounds = mapController!.bounds!;
     if(bounds.southEast != null && bounds.southWest != null && bounds.northEast != null && bounds.southEast != null ){
       CatService.loadCatByCity(city).then((value) {
          cats.clear();
          cats.add(initVal);
          for(dynamic cat in value!){
            if(cat['category'] != null){
              cats.add(cat!);
            }
          }
       });
     }
   }



   void refreshLocationForCat(){
    loadLocationsBound();
    //  if(subDropdownValue == "-1"){
    //    LocationService.loadLocationsFor(dropdownValue, currentCat[0]).then((value){
    //       locations.clear();
    //       locations.add(value!);
    //       is_loading.value = false;
    //    });
    //    print("loading main------");
    //  } 
    //  else{
    //    LocationService.loadLocationsSubFor(subDropdownValue, currentCat[0]).then((value){
    //       locations.clear();
    //       locations.add(value!);
    //       is_loading.value = false;
    //    });
    //    print("loading sub------");
    //  }
   }

  void loadAreaFor(String perf){
    areas.clear();
    dynamic initVal = {'id':'-1', 'area_nm':'----'};
    PerfectureService.loadGifuAreas(perf).then((value){
      value!.add(initVal);
      areas.add(value);
    });
  }

  void loadUserDetails(){
    if(currentUser.length > 0){
      int user_id = currentUser[0]["user"]["id"] as int;
      AuthService.UserDetails(user_id).then((value){
        print("--------- user details ----- ${value}");
        if(value != null && value.isNotEmpty){
          bool paid = value![0]["paid"] as bool;
          if(paid){
            loadCustomAreas();
          }
        }
      });
    }
  }


  void loadCustomAreas(){
    customAreas.clear();
    PerfectureService.loadCustomAreas().then((value){
      print("--- loading custom areas ${value}");
      customAreas.add(value);
    });
  }


  void loadSubPerfFor(String perf){
    subPerfs.clear();
    dynamic initVal = {'id':'-1', 'adm2_ja':'----'};
    PerfectureService.loadSubPerfectures(perf).then((value){
      value!.add(initVal);
      subPerfs.add(value);
      subDropdownValue = getSubInitialVal();
    });
  }

  String getSubInitialVal(){
    int min = 0;
    if(subPerfs.length > 0){
      min = int.parse(subPerfs[0][0]['id'].toString());
      for(var sub in subPerfs[0]){
        int x = int.parse(sub['id'].toString()); // as int;
        if(x < min){
          min = x;
        }
      }
    }
    return min.toString();
  }

  void loadLocationforPerf(String perf, MapController mapController) async {
    String cat = currentCat.isNotEmpty == true ? currentCat[0] : "";
    print(currentCat);
    // LocationService.loadLocationsFor(perf, cat).then((value){
    //   locations.clear();
    //   locations.add(value!);
    //    mapController.fitBounds(currentBound[0]);
    // });
    locations.clear();
    mapController.fitBounds(currentBound[0]);
  }

  void loadLocationforSubPerf(String subperf, MapController mapController) async {
    String cat = currentCat.isNotEmpty == true ? currentCat[0] : "";
    if(currentCat.isNotEmpty && currentCat[0] == "-all-"){
      cat = "";
    }
    LocationService.loadLocationsSubFor(subperf, cat).then((value){
      locations.clear();
      locations.add(value!);
    });
  }

  void loadCustomLocation(String customarea) async {
    String cat = currentCat.isNotEmpty == true ? currentCat[0] : "";
    if(currentCat.isNotEmpty && currentCat[0] == "-all-"){
      cat = "";
    }
    print("----- ${customarea}");
    LocationService.loadCustomLocations(customarea, cat).then((value){
      locations.clear();
      locations.add(value!);
      List<LatLng> locs = getLocationsList();
      LatLngBounds bounds = boundsFromLatLngList(locs);
      mapController!.fitBounds(bounds);
      setBound(bounds);
      Future.delayed(Duration(microseconds: 400), () {
        mapController!.fitBounds(bounds);
      });
      
    });
  }

  void loadLocationsBound(){
    if(is_custom_area_selected.value == true){
      return;
    }
    locations.clear();
    String cat = currentCat.isNotEmpty ? currentCat[0] : "";
    if(currentCat.isNotEmpty && currentCat[0] == "-all-"){
      cat = "";
    }
    LatLngBounds bounds = mapController!.bounds!;
    currentBound.clear();
    currentBound.add(bounds);
    //print(currentCat);
    if(bounds.southEast != null && bounds.southWest != null && bounds.northEast != null && bounds.southEast != null ){
      LocationService.loadLocationsBound(bounds.southWest!.latitude, bounds.southWest!.longitude, bounds.northWest.latitude, bounds.northWest.longitude, bounds.northEast!.latitude, bounds.northEast!.longitude, bounds.southEast.latitude, bounds.southEast.longitude, cat).then((value){
      //print("---value length ------ ${value!.collection.length}");
      if(value == null){
        return;
      }
      if(value != null && value.collection.isEmpty){
        if(showPopup == false) {
          return;
        }
        Get.snackbar(
              "Too many Points",
               "please zoom in",
               icon: Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
               snackPosition: SnackPosition.TOP,
               duration: Duration(milliseconds: 800),
               backgroundColor: Colors.yellow,
               //icon:Image(image:AssetImage("assets/images/dora.png"))
               );
        showPopup = false;
        //Get.showSnackbar(GetSnackBar(message: "Too many points, please zoom in",));
      }
      if(value != null && value.collection.isNotEmpty){
          //print("---- added---");
          locations.add(value);
          loadCatsv2();
        }
      });
    }
    
  }

  void setBound(LatLngBounds bounds){
    currentBound.clear();
    currentBound.add(bounds);
  }

  void zoomtoMainPerf(String id){
    
    PerfectureService.getMainPerfExt(id).then((value){
      LatLng lat1 = LatLng(value![1], value[0]);
      LatLng lat2 = LatLng(value[3], value[2]);
      LatLngBounds bound = LatLngBounds(lat1, lat2);
      mapController!.fitBounds(bound);
      setBound(bound);
    });
    
  }

  void zoomtoSubPerf(String id){

    print("zooooom");
    
    PerfectureService.getSubExt(id).then((value){
      LatLng lat1 = LatLng(value![1], value[0]);
      LatLng lat2 = LatLng(value[3], value[2]);
      LatLngBounds bound = LatLngBounds(lat1, lat2);
      mapController!.fitBounds(bound);
      setBound(bound);
    });
    
  }


  void populateForPerf(String perf, MapController mapController){
    loadSubPerfFor(perf);
    loadLocationforPerf(perf, mapController);
    zoomtoMainPerf(perf);
    is_loading.value = false;
  }

  void populateForSubPerf(String subperf, MapController mapController){
    //subDropdownValue = subperf;
    loadLocationforSubPerf(subperf, mapController);
    zoomtoSubPerf(subperf);
    is_loading.value = false;
  }

  void populateSubPerForArea(String area, MapController mapController){
    loadSubPerfFor(area);
    //loadCustomLocation("cus", mapController);
    //zoomtoSubPerf(subperf);
    is_loading.value = false;
  }

  
  GeoJsonFeature? getFeatureForLatLong(double lat, double long){
      if(locations.length > 0){
          for(GeoJsonFeature i in locations[0].collection){
            GeoJsonMultiPoint p = i.geometry as GeoJsonMultiPoint;
            if(p.geoSerie!.geoPoints[0].latitude == lat && p.geoSerie!.geoPoints[0].longitude  == long){
              return i;
          }
        }
      }
  }

  void getAction(){
    //print(currentUser[0]["user"]["id"]);
    //print(currentFeature[0].properties!["location_id"]);
    if(currentUser.length == 0){
      return;
    }
    int user_id = currentUser[0]["user"]["id"] as int;
    print("---- loc id ${currentFeature[0].properties}");
    int location_id = currentFeature[0].properties!["location_id"] as int;
    ActionService.userAction(user_id, location_id).then((value){
      print("------${value}");
      if(value != null && value.length > 0){
        currentAction.clear();
        currentAction.add(value);
        print("------${currentAction[0]}");
      }else{
        List<dynamic> initval = [{"user": user_id, "location": location_id, "wanttogo": false, "like": false, "checkin": false}];
        currentAction.clear();
        currentAction.add(initval);
      }
    });
  }

  void makeNext(GeoJsonFeature fs){

    if(rog_mode == 1){
      DestinationController destinationController = Get.find<DestinationController>();
    }
    else {
      GeoJsonFeature<GeoJsonMultiPoint> pt = fs  as GeoJsonFeature<GeoJsonMultiPoint>;

    for(int i=0; i<= locations[0].collection.length - 1; i++){
      GeoJsonMultiPoint p = locations[0].collection[i].geometry as GeoJsonMultiPoint;

      if(p.geoSerie!.geoPoints[0].latitude == pt.geometry!.geoSerie!.geoPoints[0].latitude && p.geoSerie!.geoPoints[0].longitude  == pt.geometry!.geoSerie!.geoPoints[0].longitude ){
          
          if(currentFeature.length > 0){
            currentFeature.clear();
          }
          if(i >= locations[0].collection.length - 1 ){
            currentFeature.add(locations[0].collection[0] as GeoJsonFeature);
            getAction();
          }
          else{
            currentFeature.add(locations[0].collection[i + 1] as GeoJsonFeature);
            getAction();
          }
      }
    }
    }

    

  }

  void makePrevious(GeoJsonFeature fs){

    if(rog_mode == 1){
      DestinationController destinationController = Get.find<DestinationController>();
    }
    else {

          GeoJsonFeature<GeoJsonMultiPoint> pt = fs  as GeoJsonFeature<GeoJsonMultiPoint>; 

      for(int i=0; i<= locations[0].collection.length - 1; i++){
        GeoJsonMultiPoint p = locations[0].collection[i].geometry as GeoJsonMultiPoint;

        if(p.geoSerie!.geoPoints[0].latitude == pt.geometry!.geoSerie!.geoPoints[0].latitude && p.geoSerie!.geoPoints[0].longitude  == pt.geometry!.geoSerie!.geoPoints[0].longitude ){
            
            if(currentFeature.length > 0){
              currentFeature.clear();
            }
            if(i == 0 ){
              currentFeature.add(locations[0].collection[locations[0].collection.length -1] as GeoJsonFeature);
              getAction();
            }
            else{
              currentFeature.add(locations[0].collection[i - 1] as GeoJsonFeature);
              getAction();
            }
        }
      }
    }
  }



}