import 'dart:async';

import 'package:flutter/foundation.dart' show ChangeNotifier;
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/location_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;

import 'PlacePrediction.dart';

class LocationViewModel extends ChangeNotifier {
  final LocationRepo locationRepo;
  final ErrorHandlerService errorHandlerService;

  LocationViewModel({required this.locationRepo, required this.errorHandlerService}) {
  }

  List<PlacePrediction> predictions = [];
  PlacePrediction? selectedPrediction;
  bool isPredictionLoading = false;
  GeocodeResponse? geocodeResponse;
  PlaceDetails? placeDetails;

  Location? mapCapturedLocation;

  Completer<GMSMapServices.GoogleMapController>? gmsController;
  Completer<HMSCameraServices.HuaweiMapController>? hmsController;
  get isGMSAvailable {
    return getIt.get<AppState>().isGMSAvailable;
  }
  HMSCameraServices.CameraPosition getHMSLocation() {
    return HMSCameraServices.CameraPosition(target: HMSCameraServices.LatLng(getIt<AppState>().userLat, getIt<AppState>().userLong), zoom: 18);
  }

  GMSMapServices.CameraPosition getGMSLocation() {
    return GMSMapServices.CameraPosition(
        target: GMSMapServices.LatLng(getIt<AppState>().userLat != 0.0 ? getIt<AppState>().userLat : 24.7248316, getIt<AppState>().userLong != 0.0 ? getIt<AppState>().userLong : 46.4928828),
        zoom: 18);
  }

  void placeValueInController() async {
    if (isGMSAvailable) {
      gmsController = Completer<GMSMapServices.GoogleMapController>();
    } else {
      hmsController = Completer<HMSCameraServices.HuaweiMapController>();
    }
  }

  FutureOr<void> getPlacesPrediction(String input) async {
    predictions = [];
    isPredictionLoading = true;
    final result = await locationRepo.getPlacePredictionsAsInput(input);
    result.fold(
      (failure) {
        errorHandlerService.handleError(failure: failure);
      },
      (apiModel) {
        predictions = apiModel.data ?? [];
      },
    );
    isPredictionLoading = false;
    notifyListeners();
  }

  FutureOr<void> getPlaceEncodedData(double? lat, double? lng) async {
    geocodeResponse = null;
    final result = await locationRepo.getGeoCodeFromLatLng(lat!, lng!);
    result.fold(
      (failure) {
        errorHandlerService.handleError(failure: failure);
      },
      (apiModel) {
        print("Geocode Response: ${apiModel.data}");
        geocodeResponse = apiModel.data;
      },
    );
    notifyListeners();
  }

  FutureOr<void> getPlaceDetails(String placeID) async {
    placeDetails = null;
    final result = await locationRepo.getPlaceDetailsOfSelectedPrediction(placeID);
    result.fold(
      (failure) {
        errorHandlerService.handleError(failure: failure);
      },
      (apiModel) {
        placeDetails = apiModel.data;
      },
    );
    notifyListeners();
  }

  handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) {
    mapCapturedLocation = Location(lat: value.target.latitude, lng: value.target.longitude);
  }

  handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) {
    mapCapturedLocation = Location(lat: value.target.lat, lng: value.target.lng);
  }

  handleOnCameraIdle() {
    if (mapCapturedLocation != null) {
      getPlaceEncodedData(mapCapturedLocation!.lat, mapCapturedLocation!.lng);
    }
  }

  void updateSearchQuery(String? value) {
    if (value == null || value.isEmpty) {
      predictions = [];
      return;
    }

    getPlacesPrediction(value);
  }

  void flushSearchPredictions() {
    predictions = [];
    mapCapturedLocation = null;
    placeDetails = null;
    geocodeResponse = null;
    selectedPrediction = null;

    notifyListeners();
  }

  FutureOr<void> selectPlacePrediction(PlacePrediction placePrediction) async {
    selectedPrediction = placePrediction;
    await getPlaceDetails(placePrediction.placeID);
  }

  void moveToCurrentLocation() {
    moveController(Location(lat: getIt<AppState>().userLat, lng: getIt<AppState>().userLong));
  }

  void moveController(Location location) {
    if (getIt<AppState>().isGMSAvailable) {
      gmsController?.future.then((controller) {
        controller.animateCamera(
          GMSMapServices.CameraUpdate.newCameraPosition(
            GMSMapServices.CameraPosition(
              target: GMSMapServices.LatLng(location.lat, location.lng),
              zoom: 18,
            ),
          ),
        );
      });
    } else {
      print("hmsController is null or not $hmsController");

      hmsController?.future.then((controller) {
        controller.animateCamera(
          HMSCameraServices.CameraUpdate.newCameraPosition(
            HMSCameraServices.CameraPosition(
              target: HMSCameraServices.LatLng(location.lat, location.lng),
              zoom: 18,
            ),
          ),
        );
      });
    }
  }
}
