import 'dart:async';
import 'package:dio/dio.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client.dart';
import '../base/base_response_model.dart';
import '../base/base_view_model.dart';
import '../configs/constants.dart';
import 'app_navigator.dart';
import 'dio_http_service.dart';
import 'error_mapper.dart';
import 'interceptor/network_error_gate.dart';

typedef ApiCall<T> = Future<BaseResponseModel<T>> Function();
typedef OnSuccess<T> = FutureOr<void> Function(T data, BaseResponseModel<T> res);
typedef OnFailure<T> = FutureOr<void> Function(String message, BaseResponseModel<T>? res, Object? error);
typedef OnComplete = FutureOr<void> Function();
typedef ApiTask = Future<void> Function();

class RestfulApiViewModel extends BaseViewModel {
  final RestfulAPIClient _apiService = RestfulAPIClient(DioHttpService().dio);
  RestfulAPIClient get client => _apiService;

  Future<void> callApi<T>({
    required ApiCall<T> request,
    required OnSuccess<T> onSuccess,
    OnFailure<T>? onFailure,
    OnComplete? onComplete,
    bool showAppNavigatorDialog = false,
    bool withLoading = true,
    String defaultError = ErrorCodes.commonError,
  }) async {
    if (withLoading) showLoading();
    BaseResponseModel<T>? res;
    try {
      res = await request();
      if (res.isSuccess) {
        final T data = res.data as T;
        await onSuccess(data, res);
      } else {
        final msg = res.errorMessage ?? defaultError;
        final hasInternet = await NetworkConnectivity().hasInternet();
        if (hasInternet) {
          if (showAppNavigatorDialog) {
            AppNavigator.showAlertError(content: msg);
          } else {
            await onFailure?.call(msg, res, null);
          }
        }
      }
    } catch (e) {
      String msg = defaultError;
      if (e is DioException) {
        final mapped = e.requestOptions.extra['mapped_error'];
        msg = (mapped is String && mapped.isNotEmpty) ? mapped : ErrorMapper.map(e);
      } else {
        msg = ErrorMapper.map(e);
      }
      final hasInternet = await NetworkConnectivity().hasInternet();
      if (hasInternet) {
        if (showAppNavigatorDialog) {
          AppNavigator.showAlertError(content: msg);
        } else {
          await onFailure?.call(msg, res, null);
        }
      }
    } finally {
      if (withLoading) hideLoading();
      onComplete?.call();
    }
  }

  Future<void> runAllApis({
    required List<ApiTask> tasks,
    OnComplete? onComplete,
    bool withLoading = true,
  }) async {
    if (withLoading) showLoading();
    try {
      final futures = tasks.map((t) => t()).toList();
      await Future.wait(futures);
    } finally {
      if (withLoading) hideLoading();
      onComplete?.call();
    }
  }
}