import 'dart:async';
import 'dart:io';

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_polyline_points/flutter_polyline_points.dart';
import 'package:geojson_vi/geojson_vi.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:gifunavi/model/destination.dart';
import 'package:gifunavi/model/entry.dart';
import 'package:gifunavi/pages/destination/destination_controller.dart';
import 'package:gifunavi/pages/team/team_controller.dart';
import 'package:gifunavi/routes/app_pages.dart';
import 'package:gifunavi/services/auth_service.dart';
import 'package:gifunavi/services/location_service.dart';
import 'package:gifunavi/utils/database_helper.dart';
import 'package:gifunavi/widgets/debug_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'package:gifunavi/services/api_service.dart';
import 'package:gifunavi/model/user.dart';



import 'package:gifunavi/main.dart';

import 'package:gifunavi/widgets/helper_dialog.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;

import '../permission/permission.dart';

class IndexController extends GetxController with WidgetsBindingObserver {
  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;

  double currentLat = 0.0, currentLon = 0.0;

  var isLoading = false.obs;

  var isRogMapcontrollerLoaded = false.obs;

  var isCustomAreaSelected = false.obs;

  RxBool isMapControllerReady = RxBool(false);			// MapControllerの初期化状態を管理するフラグ
  //final mapControllerReadyStream = Stream<bool>.value(false);	// MapControllerの初期化状態を通知するためのストリーム

  MapController mapController = MapController();
  MapController rogMapController = MapController();

  LogManager logManager = LogManager();

  String? userToken;

  //late final ApiService _apiService;
  final ApiService _apiService; // = Get.find<ApiService>();
  final DatabaseHelper _dbHelper = DatabaseHelper.instance;

  IndexController({
    required ApiService apiService,
  }) : _apiService = apiService;


  // mode = 0 is map mode, mode = 1 list mode
  var mode = 0.obs;

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

  var desinationMode = 1.obs;

  bool showPopup = true;

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

  final selectedEventName = 'add_location'.tr.obs;

  RxBool isLoadingLocations = true.obs;

  void setSelectedEventName(String eventName) {
    selectedEventName.value = eventName;
  }

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

  final Rx<DateTime> lastUserUpdateTime = DateTime.now().obs;

  RxInt teamId = RxInt(-1); // チームIDを保存するための変数

  //late TeamController teamController = TeamController();
  /*
  void updateUserInfo(Map<String, dynamic> newUserInfo) {
    currentUser.clear();
    currentUser.add(newUserInfo);
    lastUserUpdateTime.value = DateTime.now();
  }
   */

  final isReferenceMode = false.obs;

  void setReferenceMode(bool value) {
    isReferenceMode.value = value;
  }

  bool canStartRoge() {
    return !isReferenceMode.value;
  }

  bool canCheckin() {
    return !isReferenceMode.value;
  }

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

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

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

  Future<void> _checkLocationPermission() async {
    if (Get.context == null) {
      debugPrint('Get.context is null in _checkLocationPermission');
      return;
    }
      LocationPermission permission = await Geolocator.checkPermission();
    //permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
          debugPrint('GPS : Denied');
          await showLocationPermissionDeniedDialog();
      } else if (permission == LocationPermission.deniedForever) {
        debugPrint('GPS : Denied forever');
        await showLocationPermissionDeniedDialog();
      }else if (permission == LocationPermission.whileInUse){
        debugPrint('GPS : While-In-Use');
        await showLocationPermissionDeniedDialog();

      }else{
        debugPrint("Permission is no problem....");
      }
  }


  // 追加
  Future<void> showLocationPermissionDeniedDialog() async {
    if (Get.context != null) {
      print('Showing location permission denied dialog');
      await showDialog(
        context: Get.context!,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return WillPopScope(
            onWillPop: () async => false,
            child: AlertDialog(
              title: Text('location_permission_needed_title'.tr),
              content: Text('location_permission_needed_main'.tr),
              actions: [
                TextButton(
                  onPressed: () {
                    logManager.addOperationLog("User tapped confirm button for location permission required.");
                    Navigator.of(context).pop();
                  },
                  child: Text('confirm'.tr),
                ),
              ],
            ),
          );
        },
      );
    } else {
      print('Get.context is null in showLocationPermissionDeniedDialog');
      // Get.contextがnullの場合の処理
      print('Location permission denied, but context is null');
    }
  }


  @override
  void onInit() {
    try {
      super.onInit();
      initConnectivity();
      _connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);

      WidgetsBinding.instance.addPostFrameCallback((_) async {
        await PermissionController.checkAndRequestPermissions();
      });

      WidgetsBinding.instance.addObserver(this);
      _startLocationService(); // アプリ起動時にLocationServiceを開始する

      initializeApiService();

      print('IndexController onInit called'); // デバッグ用の出力を追加

      tz.initializeTimeZones();
      //teamController = Get.find<TeamController>();

      loadLocations();

    }catch(e,stacktrace){
      print('Error in IndexController.onInit: $e');
      print('Stack trace: $stacktrace');
      // エラーレポートサービスにエラーを送信
      //ErrorService.reportError(e, stackTrace, deviceInfo, LogManager().operationLogs);

    }
  }

  Future<void> loadLocations() async {
    isLoadingLocations.value = true;
    try {
      await waitForMapControllerReady();
      String eventCode = currentUser.isNotEmpty ? currentUser[0]["user"]["event_code"] ?? "" : "";
      await loadLocationsBound(eventCode);
    } catch (e) {
      print('Error loading locations: $e');
      // エラーハンドリングを追加（例：スナックバーでユーザーに通知）
    } finally {
      isLoadingLocations.value = false;
    }
  }

  void _updateConnectionStatus(List<ConnectivityResult> results)  {

    final result = results.isNotEmpty ? results.first : ConnectivityResult.none;
    connectionStatus.value = result;

    switch (result) {
      case ConnectivityResult.wifi:
        connectionStatusName.value = "WiFi";
        break;
      case ConnectivityResult.mobile:
        connectionStatusName.value = "mobile";
        break;
      case ConnectivityResult.none:
        connectionStatusName.value = "offline";
        break;
      default:
        connectionStatusName.value = "不明";
        break;
    }

    logManager.addOperationLog("Connection status changed to: ${connectionStatusName.value}");

    if (result != ConnectivityResult.none) {
      _handleConnectionRestored();
    }
  }

  Future<void> _handleConnectionRestored() async {
    await _syncPendingData();
  }

  Future<void> initConnectivity() async {
    try {
      final result = await _connectivity.checkConnectivity();
      _updateConnectionStatus(result); // リストとして渡す
    } on PlatformException catch (e) {
      print('Couldn\'t check connectivity status: ${e.message}');
    }
  }

// 保留中のデータを同期する例のメソッド
  Future<void> _syncPendingData() async {
    // ここに保留中のデータを同期するロジックを実装
    // 例: ローカルDBに保存された未送信のデータをサーバーに送信する
    try {
      // 同期処理
      logManager.addOperationLog("Syncing pending data");
      // 同期ロジックをここに実装
    } catch (e) {
      logManager.addOperationLog("Error syncing pending data: $e");
      // エラーハンドリング
    }
  }

  Future<void> initializeApiService() async {
    if (currentUser.isNotEmpty) {
      // 既にログインしている場合
      await Get.putAsync(() => ApiService().init());
      //await Get.putAsync(() => ApiService().init());
      // 必要に応じて追加の初期化処理
    }
  }

/*
  void checkPermission()
  {
      debugPrint("MapControllerの初期化が完了したら、位置情報の許可をチェックする");
      _checkLocationPermission();
  }
*/

  @override
  void onClose() {
    _connectivitySubscription.cancel();
    WidgetsBinding.instance.removeObserver(this);
    _stopLocationService(); // アプリ終了時にLocationServiceを停止する
    super.onClose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {

    if (state == AppLifecycleState.resumed) {
      if (!_isLocationServiceRunning()) {
        _startLocationService();
      }
    } else if (state == AppLifecycleState.paused) {
      _stopLocationService();
    }
  }

  bool _isLocationServiceRunning() {
    // LocationServiceが実行中かどうかを確認する処理を実装する
    // 例えば、SharedPreferencesにサービスの状態を保存するなど
    // ここでは簡単のために、常にfalseを返すようにしています
    return false;
  }

  void _startLocationService() async {
    if (Platform.isAndroid) {
      const platform = MethodChannel('location');
      try {
        logManager.addOperationLog("Called start location service.");
        await platform.invokeMethod('startLocationService');
      } on PlatformException catch (e) {
        print("Failed to start location service: '${e.message}'.");
      }
    }else if (Platform.isIOS) {
      // iOSの位置情報サービス開始ロジック
      // 例: geolocatorプラグインを使用する場合
      try {
        bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
        if (!serviceEnabled) {
          // 位置情報サービスが無効の場合の処理
          return;
        }
        // 位置情報の権限確認と取得開始
        LocationPermission permission = await Geolocator.checkPermission();
        if (permission == LocationPermission.denied) {
          permission = await Geolocator.requestPermission();
          if (permission == LocationPermission.denied) {
            // 権限が拒否された場合の処理
            return;
          }
        }
        // 位置情報の取得開始
        Geolocator.getPositionStream().listen((Position position) {
          // 位置情報を使用した処理
        });
      } catch (e) {
        print('Error starting iOS location service: $e');
      }
    }
  }

  void _stopLocationService() async {
    if (Platform.isAndroid) {
      const platform = MethodChannel('location');
      try {
        logManager.addOperationLog("Called stop location service.");
        await platform.invokeMethod('stopLocationService');
      } on PlatformException catch (e) {
        print("Failed to stop location service: '${e.message}'.");
      }
    }else{
      debugPrint("stopLocation for iOS");
    }
  }

  /*
  @override
  void onReady() async {
    await readUserToken();
    final token = userToken;
    if (token != null && token.isNotEmpty) {
      await loadUserDetailsForToken(token);
      fixMapBound(token);
    } else {
      // ユーザートークンが存在しない場合はログイン画面にリダイレクト
      Get.offAllNamed(AppPages.LOGIN);
    }

    // 地図のイベントリスナーを設定
    indexController.mapController.mapEventStream.listen((MapEvent mapEvent) {
      if (mapEvent is MapEventMoveEnd) {
        indexController.loadLocationsBound();
      }
    });

    super.onReady();
  }
   */

  /*
  Future<void> initConnectivity() async {
    late ConnectivityResult result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      connectionStatus = (await _connectivity.checkConnectivity()) as ConnectivityResult;
      await _updateConnectionStatus(connectionStatus);
    } on PlatformException catch (_) {
      //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;
      }
    }

    logManager.addOperationLog("Called boundsFromLatLngList (${x1!},${y1!})-(${x0!},${y0!}).");

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

  // 要検討：エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
  //
  Future<void> login(String email, String password) async {
    try {
      final value = await AuthService.login(email, password);
      if (value.isNotEmpty && value['token'] != null) {
        await changeUser(value);
        await _initializeUserData();
        Get.offAllNamed(AppPages.INDEX);
      } else {
        Get.snackbar('Login Failed', 'Invalid credentials');
      }
    } catch (e) {
      print('Login error: $e');
      Get.snackbar('Login Failed', 'An error occurred. Please try again.');
    }
  }

  Future<void> _initializeUserData() async {
    try {
      await fetchUserEventInfo();
      await fetchTeamData();
      // 他の必要なデータ取得処理
    } catch (e) {
      print('Error initializing user data: $e');
      Get.snackbar('Error', 'Failed to load user data. Please try again.');
    }
  }


  Future<void> login_old(String email, String password, BuildContext context) async{

    try {
      AuthService.login(email, password).then((value) async {
        print("------- logged in user details ######## $value ###### --------");
        if (value.isNotEmpty && value['token']!=null) {
          logManager.addOperationLog("User logged in : $value.");

          // Navigator.pop(context);
          print("--------- user details login ----- $value");
          // ログイン成功後、api_serviceを初期化
          await Get.putAsync(() => ApiService().init());

          // ユーザー情報の完全性をチェック
          if (await checkUserInfoComplete()) {
            Get.offAllNamed(AppPages.INDEX);
          } else {
            Get.offAllNamed(AppPages.USER_DETAILS_EDIT);
          }
        } else {
          logManager.addOperationLog("User failed login : $email , $password.");
          isLoading.value = false;
          Get.snackbar(
            "login_failed".tr,
            "check_login_id_or_password".tr,
            backgroundColor: Colors.red,
            colorText: Colors.white,
            icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
            snackPosition: SnackPosition.TOP,
            duration: const Duration(seconds: 3),
            //backgroundColor: Colors.yellow,
            //icon:Image(image:AssetImage("assets/images/dora.png"))
          );
        }
      });
    } catch(e ){
      print('Login error: $e');
      Get.snackbar('Login Failed', 'An error occurred. Please try again.');
    }
  }


  // 要検討：エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
  //
  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) {
        logManager.addOperationLog("User successed to change password : $oldpassword , $newpassword.");
        isLoading.value = false;
        Navigator.pop(context);
        if (rogMode.value == 1) {
          switchPage(AppPages.TRAVEL);
        } else {
          switchPage(AppPages.INDEX);
        }
      } else {
        logManager.addOperationLog("User failed to change password : $oldpassword , $newpassword.");
        Get.snackbar(
          'failed'.tr,
          'password_change_failed_please_try_again'.tr,
            backgroundColor: Colors.red,
            colorText: Colors.white,
            icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
          snackPosition: SnackPosition.TOP,
          duration: const Duration(milliseconds: 800),
          //backgroundColor: Colors.yellow,
          //icon:Image(image:AssetImage("assets/images/dora.png"))
        );
      }
    });
    isLoading.value = false;
  }

  /*
  void logout() async {
    locations.clear();
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinations().then((value) {
      DestinationController destinationController =
          Get.find<DestinationController>();
      destinationController.populateDestinations();
    });
    currentUser.clear();
    cats.clear();

    // ユーザートークンをデバイスから削除
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove("user_token");
  }
   */

  Future<void> logout() async {
    logManager.addOperationLog("User logout : $currentUser .");
    saveGameState();
    locations.clear();
    DatabaseHelper db = DatabaseHelper.instance;
    db.deleteAllDestinationsExceptTodayCheckins().then((value) {
      DestinationController destinationController =
      Get.find<DestinationController>();
      destinationController.populateDestinations();
    });
    currentUser.clear();
    cats.clear();

    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove("user_token");
  }

  // 要検討：エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
  //
  void register(String email, String password, String password2, BuildContext context) {
    AuthService.register(email, password,password2).then((value) {
      if (value.containsKey("error")) {
        String errMessage = value["error"];
        debugPrint("ユーザー登録失敗：$email, $password,$errMessage");
        logManager.addOperationLog("User failed to register new account : $email , $password ,$errMessage.");
        isLoading.value = false;
        Get.snackbar(
          'user_registration_failed_please_try_again'.tr,   // ユーザー登録に失敗しました。
          errMessage,
          backgroundColor: Colors.red,
          colorText: Colors.white,
          icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
          snackPosition: SnackPosition.TOP,
          duration: const Duration(seconds: 3),
          //backgroundColor: Colors.yellow,
          //icon:Image(image:AssetImage("assets/images/dora.png"))
        );
      }else{
        debugPrint("ユーザー登録成功：$email, $password");
        logManager.addOperationLog("User tried to register new account : $email , $password .");

        currentUser.clear();
        //currentUser.add(value);
        isLoading.value = false;

        // ユーザー登録成功メッセージを表示
        Get.snackbar(
          'success'.tr,
          'user_registration_successful'.tr,
          backgroundColor: Colors.green,
          colorText: Colors.white,
          snackPosition: SnackPosition.TOP,
          duration: const Duration(seconds: 3),
        );

        //Navigator.pop(context);
        Get.toNamed(AppPages.LOGIN);
      }
    });
  }

  void saveToDevice(String val) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString("user_token", val);
    print("saveToDevice: $val");
  }

  /*
  void changeUser(Map<String, dynamic> value, {bool replace = true}) {
    print("---- change user to $value -----");
    currentUser.clear();
    currentUser.add(value);
    if (replace) {
      saveToDevice(currentUser[0]["token"]);
    }
    isLoading.value = false;
    loadLocationsBound();
    if (currentUser.isNotEmpty) {
      rogMode.value = 0;
    } else {
      rogMode.value = 1;
    }
    print('--- c rog mode --- ${rogMode.value}');
    Get.toNamed(AppPages.INDEX);
  }
   */

  Future<void> changeUser(Map<String, dynamic> value, {bool replace = true}) async{
    try {
      if (value['user'] == null || value['token'] == null) {
        throw Exception('Invalid user data');
      }
      currentUser.clear();
      currentUser.add(value);
      if (replace) {
        saveToDevice(currentUser[0]["token"]);
      }
      isLoading.value = false;

      // ユーザーのイベント情報を取得
      await fetchUserEventInfo();

      loadLocationsBound(currentUser[0]["user"]["event_code"]);
      if (currentUser.isNotEmpty) {
        rogMode.value = 0;
        restoreGame();

        // チームデータを取得
        await fetchTeamData();
      } else {
        rogMode.value = 1;
      }
      Get.toNamed(AppPages.INDEX);
    } catch( e ){
      print('Error in changeUser: $e');
      Get.snackbar('Error', 'Failed to update user information');
    }
  }

  Future<bool> checkUserInfoComplete() async {
    try {
      final user = await ApiService.to.getCurrentUser();
      return user.firstname.isNotEmpty &&
          user.lastname.isNotEmpty &&
          user.dateOfBirth != null;
    } catch (e) {
      print('Error checking user info: $e');
      return false;
    }
  }

  Future<void> fetchUserEventInfo() async {
    try {
      final List<Entry> entries = await _apiService.getEntries();

      if (entries.isNotEmpty) {
        final Entry latestEntry = entries.last;

        final tokyo = tz.getLocation('Asia/Tokyo');
        final eventDate = latestEntry.date!.toUtc();
        //final eventDate = tz.TZDateTime.from(utcDate, tokyo);

        final eventDateOnly = tz.TZDateTime(tokyo, eventDate.year, eventDate.month, eventDate.day);

        currentUser[0]['user']['event_date'] = eventDateOnly.toIso8601String().split('T')[0];
        currentUser[0]['user']['event_code'] = latestEntry.event.eventName;
        currentUser[0]['user']['team_name'] = latestEntry.team.teamName;
        currentUser[0]['user']['group'] = latestEntry.team.category.categoryName;
        currentUser[0]['user']['zekken_number'] = latestEntry.zekkenNumber;

        // 最後のゴール日時を取得
        final lastGoalTime = await getLastGoalTime();
        currentUser[0]['user']['last_goal_time'] = lastGoalTime?.toIso8601String();

        print('Updated user event info: ${currentUser[0]['user']}');
      } else {
        print('No entries found for the user');
        _clearUserEventInfo();
      }
    } catch (e) {
      print('Error fetching user event info: $e');
      _clearUserEventInfo();
    }
  }

  Future<DateTime?> getLastGoalTime() async {
    try {
      final userId = currentUser[0]['user']['id'];
      return await _apiService.getLastGoalTime(userId);
    } catch (e) {
      print('Error getting last goal time: $e');
    }
    return null;
  }

  void _clearUserEventInfo() {
    currentUser[0]['user']['event_date'] = null;
    currentUser[0]['user']['event_code'] = null;
    currentUser[0]['user']['team_name'] = null;
    currentUser[0]['user']['group'] = null;
    currentUser[0]['user']['zekken_number'] = null;
  }

  Future<void> fetchTeamData() async {
    try {
      Get.put(TeamController(apiService:Get.find<ApiService>()));
      // \"TeamController\" not found. You need to call \"Get.put(TeamController())\" or \"Get.lazyPut(()=>TeamController())\"
      final teamController = Get.find<TeamController>();
      await teamController.fetchTeams();
      if (teamController.teams.isNotEmpty) {
        teamId.value = teamController.teams.first.id;
      }
    } catch (e) {
      print("Error fetching team data: $e");
    }
  }



  loadUserDetailsForToken(String token) async {
    AuthService.userForToken(token).then((value) {
      print("----token val-- $value  ------");
      if (value![0]["user"].isEmpty) {
        Get.toNamed(AppPages.LOGIN);
        return;
      }
      changeUser(value[0], replace: false);
    });
  }

/* Old code
  void loadLocationsBound() {
    if (isCustomAreaSelected.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);
    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.features.isEmpty) {
        if (showPopup == false) {
          return;
        }
        Get.snackbar(
          "Too many Points",
          "please zoom in",
          icon: const Icon(Icons.assistant_photo_outlined,
              size: 40.0, color: Colors.blue),
          snackPosition: SnackPosition.TOP,
          duration: const Duration(seconds: 2),
          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.features.isNotEmpty) {
        ////print("---- added---");
        locations.add(value);
      }
    });
  }
*/


  // 2024-04-03 Akira .. Update the code . See ticket 2800.
  //
  // 2024-4-8 Akira : See 2809
  // IndexControllerクラスでは、Future.delayedの呼び出しをunawaitedで囲んで、
  // 非同期処理の結果を待たずに先に進むようにしました。これにより、メモリリークを防ぐことができます
  //
  // 要検討：Future.delayedを使用して非同期処理を待たずに先に進むようにしていますが、
  // これによってメモリリークが発生する可能性があります。非同期処理の結果を適切に処理することを検討してください。
  //
  Future<void> loadLocationsBound(String eventCode) async {
    if (isCustomAreaSelected.value == true) {
      return;
    }

    // MapControllerの初期化が完了するまで待機
    await waitForMapControllerReady();

    // null チェックを追加
    if (mapController.bounds == null) {
      print("MapController bounds are null");
      return;
    }

    // バウンドが有効かどうかを確認する
    LatLngBounds bounds = mapController.bounds!;
    if (!_isValidBounds(bounds)) {
      print("MapController bounds are not valid");
      return;
    }

    locations.clear();
    String cat = currentCat.isNotEmpty ? currentCat[0] : "";
    if (currentCat.isNotEmpty && currentCat[0] == "-all-") {
      cat = "";
    }
/*
    // Akira Add 2024-4-6
    if( mapController.controller == null ) {
	print("操作が完了する前にMapControllerまたはウィジェットが破棄されました。");
	isLoading.value = true; // ローディング状態をtrueに設定
	return;
    }
    //
*/

    //LatLngBounds bounds = mapController.bounds!;

    currentBound.clear();
    currentBound.add(bounds);
  
    //isLoading.value = true; // ローディング状態をtrueに設定
  
      //print("bounds --- (${bounds.southWest.latitude},${bounds.southWest.longitude}),(${bounds.northWest.latitude},${bounds.northWest.longitude}),(${bounds.northEast.latitude},${bounds.northEast.longitude}),(${bounds.southEast.latitude},${bounds.southEast.longitude})");

      // 要検討：APIからのレスポンスがnullの場合のエラーハンドリングが不十分です。適切なエラーメッセージを表示するなどの処理を追加してください。
      try {
        final eventCode = currentUser[0]["user"]["event_code"];
        final value = await 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,
          eventCode
        );
        /*
        if (value == null) {
          // APIからのレスポンスがnullの場合
          print("LocationService.loadLocationsBound からの回答がnullのため、マップをリロード");
          DestinationController destinationController = Get.find<DestinationController>(); // 追加
          final tk = currentUser[0]["token"]; // 追加
          if (tk != null) { // 追加
            destinationController.fixMapBound(tk); // 追加
          } // 追加
          return;
        }
         */
        isLoading.value = false; // ローディング状態をfalseに設定

        if (value == null) {
          // APIからのレスポンスがnullの場合
          print("LocationService.loadLocationsBound からの回答がnullです");
        } else {
          if (value.features.isEmpty) {
            if (showPopup == false) {
              return;
            }
            Get.snackbar(
              "Too many Points",
              "please zoom in",
              backgroundColor: Colors.yellow,
              colorText: Colors.white,
              icon: const Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
              snackPosition: SnackPosition.TOP,
              duration: const Duration(seconds: 3),
            );
            showPopup = false;
          }
          if (value.features.isNotEmpty) {
            locations.add(value);
          }
        }
        /*
        if (value != null && value.features.isEmpty) {
          if (showPopup == false) {
            return;
          }
          Get.snackbar(
            "Too many Points",
            "please zoom in",
              backgroundColor: Colors.yellow,
              colorText: Colors.white,
              icon: const Icon(
                Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
            snackPosition: SnackPosition.TOP,
            duration: const Duration(seconds: 3),
            //backgroundColor: Colors.yellow,
          );
          showPopup = false;
        }
        if (value != null && value.features.isNotEmpty) {
          locations.add(value);
        }
         */
      } catch ( e) {
        print("Error in loadLocationsBound: $e");
        // エラーが発生した場合のリトライ処理や適切なエラーメッセージの表示を行う
        // 例えば、一定時間後に再度loadLocationsBound()を呼び出すなど
      }

  }

  // バウンドが有効かどうかを確認するヘルパーメソッド
  bool _isValidBounds(LatLngBounds bounds) {
    // 緯度と経度が有効な範囲内にあるかチェック
    return bounds.southWest.latitude.abs() <= 90 &&
        bounds.southWest.longitude.abs() <= 180 &&
        bounds.northEast.latitude.abs() <= 90 &&
        bounds.northEast.longitude.abs() <= 180 &&
        bounds.southWest.latitude < bounds.northEast.latitude;
  }

  //===Akira 追加:2024-4-6 #2800
  // 要検討：MapControllerの初期化が完了するまで待機していますが、タイムアウトを設定することを検討してください。
  // 初期化に時間がかかりすぎる場合、ユーザーにわかりやすいメッセージを表示するようにしてください。
  //
  Future<void> waitForMapControllerReady() async {
    if (!isMapControllerReady.value) {
      await Future.doWhile(() async {
        await Future.delayed(const Duration(milliseconds: 100));
        return !isMapControllerReady.value;
      });
    }
  }
  //===Akira 追加:2024-4-6 #2800

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

  GeoJSONFeature? getFeatureForLatLong(double lat, double long) {
    if (locations.isNotEmpty) {
      GeoJSONFeature? foundFeature;

      for (var i in locations[0].features) {
        GeoJSONMultiPoint p = i!.geometry as GeoJSONMultiPoint;
        if (p.coordinates[0][1] == lat && p.coordinates[0][0] == long) {
          foundFeature = i;
        }
      }

      return foundFeature;
    }
    return null;
  }


  void reloadMap( String eventCode ) {
    // マップをリロードするロジックを実装
    // 例: 現在の位置情報を再取得し、マップを更新する
    loadLocationsBound( eventCode );
  }

  Future<void> checkEntryData() async {
    // エントリーデータの有無をチェックするロジック
    final teamController = TeamController(apiService:Get.find<ApiService>());
    bool hasEntryData = teamController.checkIfUserHasEntryData();
    if (!hasEntryData) {
      await showHelperDialog(
          'イベントに参加するには、チーム登録・メンバー登録及びエントリーが必要になります。',
          'entry_check'
      );
      // ドロワーを表示するロジック
      Get.toNamed('/drawer');
    }
  }

  void updateCurrentUser(User updatedUser) {
    currentUser[0]['user'] = updatedUser.toJson();
    update();
  }
}
