import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';

import '../../core/api_consts.dart';
import 'PlacePrediction.dart';

abstract class LocationRepo {
  Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>>
      getPlacePredictionsAsInput(String input);

  Future<Either<Failure, GenericApiModel<PlaceDetails>>>
      getPlaceDetailsOfSelectedPrediction(String placeId);

  Future<Either<Failure, GenericApiModel<GeocodeResponse>>>
      getGeoCodeFromLatLng(double lat, double lng);
}

class LocationRepoImpl implements LocationRepo {
  final ApiClient apiClient;

  LocationRepoImpl({required this.apiClient});

  @override
  Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>> getPlacePredictionsAsInput(
      String input) async {
    final url = Uri.parse(
      'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&region=SA&key=$GOOGLE_API_KEY',
    );

    GenericApiModel<List<PlacePrediction>>? apiResponse;
    Failure? failure;

    try {
      await apiClient.get(
        url.toString(),
        isExternal: true,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['predictions'];
            final predictionsList = list
                .map((item) =>
                    PlacePrediction.fromJson(item as Map<String, dynamic>))
                .toList()
                .cast<PlacePrediction>();
            apiResponse = GenericApiModel<List<PlacePrediction>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: predictionsList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<GeocodeResponse>>> getGeoCodeFromLatLng(double lat, double lng) async {
    final url = Uri.parse(
      'https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=$GOOGLE_API_KEY',
    );


    GenericApiModel<GeocodeResponse>? apiResponse;
    Failure? failure;

    try {
      await apiClient.get(
        url.toString(),
        isExternal: true,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final predictionsList = GeocodeResponse.fromJson(response);
            apiResponse = GenericApiModel<GeocodeResponse>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: predictionsList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<PlaceDetails>>> getPlaceDetailsOfSelectedPrediction(String placeId) async {


    final url = Uri.parse(
      'https://maps.googleapis.com/maps/api/place/details/json'
          '?place_id=$placeId&fields=geometry&key=$GOOGLE_API_KEY',
    );

    GenericApiModel<PlaceDetails>? apiResponse;
    Failure? failure;

    try {
      await apiClient.get(
        url.toString(),
        isExternal: true,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final predictionsList = PlaceDetails.fromJson(response);
            apiResponse = GenericApiModel<PlaceDetails>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: predictionsList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }
}
