import 'dart:developer';

import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';

import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/extension/extension.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/analytic/analytic.dart';
import '../analytic_dtos.dart';

@injectable
class AnalyticRemoteDataProvider {
  final ApiClient _apiClient;
  final String _logName = "AnalyticRemoteDataProvider";

  AnalyticRemoteDataProvider(this._apiClient);

  Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.salesAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = SalesAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchSalesError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.profitLossAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = ProfitLossAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchProfitLossError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, CategoryAnalyticDto>> fetchCategory({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.categoryAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = CategoryAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchCategoryError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, InventoryAnalyticDto>> fetchInventory({
    required String outletId,
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        '${ApiPath.inventoryReportDetail}/$outletId',
        params: {
          'date_from': dateFrom.toServerDate,
          'date_to': dateTo.toServerDate,
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = InventoryAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchInventoryError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, DashboardAnalyticDto>> fetchDashboard({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.dashboardAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = DashboardAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchDashboardError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, ProductAnalyticDto>> fetchProduct({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.productAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = ProductAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchProductError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, PaymentMethodAnalyticDto>> fetchPaymentMethod({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.paymentMethodAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = PaymentMethodAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchPaymentMethodError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, PurchasingAnalyticDto>> fetchPurchasing({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
    String groupBy = 'day',
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
        'group_by': groupBy,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.purchasingAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = PurchasingAnalyticDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchPurchasingError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, ExclusiveSummaryDto>> fetchExclusiveSummary({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.exclusiveSummaryAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = ExclusiveSummaryDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchExclusiveSummaryError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, ProfitSharingDto>> fetchProfitSharing({
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
    String groupBy = 'day',
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
        'group_by': groupBy,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        ApiPath.parentCategoryAnalytic,
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = ProfitSharingDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log('fetchProfitSharingError', name: _logName, error: e, stackTrace: s);
      return DC.error(AnalyticFailure.serverError(e));
    }
  }

  Future<DC<AnalyticFailure, ProfitSharingDetailDto>> fetchProfitSharingDetail({
    required String parentCategoryId,
    required DateTime dateFrom,
    required DateTime dateTo,
    String? outletId,
  }) async {
    try {
      final Map<String, dynamic> params = {
        'date_from': dateFrom.toServerDate,
        'date_to': dateTo.toServerDate,
      };
      if (outletId != null) params['outlet_id'] = outletId;

      final response = await _apiClient.get(
        '${ApiPath.parentCategoryAnalytic}/$parentCategoryId',
        params: params,
        headers: getAuthorizationHeader(),
      );

      if (response.data['data'] == null) {
        return DC.error(AnalyticFailure.empty());
      }

      final dto = ProfitSharingDetailDto.fromJson(response.data['data']);

      return DC.data(dto);
    } on ApiFailure catch (e, s) {
      log(
        'fetchProfitSharingDetailError',
        name: _logName,
        error: e,
        stackTrace: s,
      );
      return DC.error(AnalyticFailure.serverError(e));
    }
  }
}
