import 'dart:developer';

import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.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/water_monitor/models/insert_user_activity_request_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/models/undo_user_activity_request_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/models/update_user_detail_request_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';

/// Progress types to request different ranges from the progress API.
enum ProgressType { today, week, month }

abstract class WaterMonitorRepo {
  /// Fetch user details for water monitoring.
  /// The request will include the standard payload injected by ApiClient and
  /// additionally these three parameters: Progress, MobileNumber, IdentificationNo.
  Future<Either<Failure, GenericApiModel<dynamic>>> getUserDetailsForWaterMonitoring({
    required num progress,
    required String mobileNumber,
    required String identificationNo,
  });

  /// Fetch user progress for water monitoring (H2O_GetUserProgress).
  Future<Either<Failure, GenericApiModel<dynamic>>> getUserProgressForWaterMonitoring({
    required ProgressType progressType,
    required String mobileNumber,
    required String identificationNo,
  });

  /// Update user details for water monitoring.
  Future<Either<Failure, GenericApiModel<dynamic>>> updateOrInsertUserDetailForWaterMonitoring(
      {required UpdateUserDetailRequestModel requestModel, bool isUpdate = false});

  /// Insert user activity (water intake).
  Future<Either<Failure, GenericApiModel<dynamic>>> insertUserActivity({
    required InsertUserActivityRequestModel requestModel,
  });

  /// Undo last user activity.
  Future<Either<Failure, GenericApiModel<dynamic>>> undoUserActivity({
    required UndoUserActivityRequestModel requestModel,
  });
}

class WaterMonitorRepoImp implements WaterMonitorRepo {
  final ApiClient apiClient;
  final LoggerService loggerService;

  WaterMonitorRepoImp({required this.loggerService, required this.apiClient});

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> getUserDetailsForWaterMonitoring({
    required num progress,
    required String mobileNumber,
    required String identificationNo,
  }) async {
    Map<String, dynamic> request = {
      "Progress": progress,
      "MobileNumber": mobileNumber,
      "IdentificationNo": identificationNo,
    };

    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.h2oGetUserDetail,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            // Extract only the specific key from the API response as requested
            dynamic extracted;
            if (response is Map && response.containsKey('UserDetailData_New')) {
              extracted = response['UserDetailData_New'];
            } else {
              extracted = null;
            }

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: extracted,
            );
          } 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<dynamic>>> getUserProgressForWaterMonitoring({
    required ProgressType progressType,
    required String mobileNumber,
    required String identificationNo,
  }) async {
    final progressValue = progressType == ProgressType.today ? 1 : (progressType == ProgressType.week ? 2 : 3);

    Map<String, dynamic> request = {
      "Progress": progressValue,
      "MobileNumber": mobileNumber,
      "IdentificationNo": identificationNo,
    };

    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.h2oGetUserProgress,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            // Extract progress data and history data
            dynamic extracted;
            dynamic historyData;

            if (response is Map) {
              // Extract history data (available for all progress types)
              if (response.containsKey('UserProgressHistoryData')) {
                historyData = response['UserProgressHistoryData'];
              }

              // Extract progress data based on type
              switch (progressType) {
                case ProgressType.today:
                  if (response.containsKey('UserProgressForTodayData')) {
                    extracted = response['UserProgressForTodayData'];
                  }
                  break;
                case ProgressType.week:
                  if (response.containsKey('UserProgressForWeekData')) {
                    extracted = response['UserProgressForWeekData'];
                  }
                  break;
                case ProgressType.month:
                  if (response.containsKey('UserProgressForMonthData')) {
                    extracted = response['UserProgressForMonthData'];
                  }
                  break;
              }

              // fallbacks
              if (extracted == null) {
                if (response.containsKey('UserProgress')) {
                  extracted = response['UserProgress'];
                } else if (response.containsKey('UserProgressData_New')) {
                  extracted = response['UserProgressData_New'];
                } else {
                  extracted = response;
                }
              }
            } else {
              extracted = response;
            }

            // Package both progress data and history data
            final combinedData = {
              'progressData': extracted,
              'historyData': historyData,
            };

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: combinedData,
            );
          } 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<dynamic>>> updateOrInsertUserDetailForWaterMonitoring({
    required UpdateUserDetailRequestModel requestModel,
    bool isUpdate = false,
  }) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;

      // Use different endpoint based on isUpdate flag
      final endpoint = isUpdate ? ApiConsts.h2oUpdateUserDetail : ApiConsts.h2oInsertUserDetailsNew;
      await apiClient.post(
        endpoint,
        body: requestModel.toJson(),
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            dynamic extracted;
            if (response is Map && response.containsKey('UserDetailData_New')) {
              extracted = response['UserDetailData_New'];
            } else {
              extracted = null;
            }

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: extracted,
            );
          } 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<dynamic>>> insertUserActivity({
    required InsertUserActivityRequestModel requestModel,
  }) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.h2oInsertUserActivity,
        body: requestModel.toJson(),
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            // Extract UserProgressForTodayData from the response
            dynamic extracted;
            if (response is Map && response.containsKey('UserProgressForTodayData')) {
              extracted = response['UserProgressForTodayData'];
            } else {
              extracted = response;
            }

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: extracted,
            );
          } 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<dynamic>>> undoUserActivity({
    required UndoUserActivityRequestModel requestModel,
  }) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.h2oUndoUserActivity,
        body: requestModel.toJson(),
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            log("response h2oUndoUserActivity: ${response.toString()}");
            // Extract UserProgressForTodayData from the response
            dynamic extracted;
            if (response is Map && response.containsKey('UserProgressForTodayData')) {
              extracted = response['UserProgressForTodayData'];
            } else {
              extracted = response;
            }

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: extracted,
            );
          } 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()));
    }
  }
}
