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 '../../../injection.dart';
import '../../outlet/datasources/local_data_provider.dart';
import '../analytic_dtos.dart';

@injectable
class AnalyticRemoteDataProvider {
  final ApiClient _apiClient;

  final _logName = 'AnalyticRemoteDataProvider';

  AnalyticRemoteDataProvider(this._apiClient);

  Future<DC<AnalyticFailure, DashboardAnalyticDto>> fetchDashboard({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticDashboard,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final dashboard = DashboardAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

  Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticSales,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final sales = SalesAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

  Future<DC<AnalyticFailure, ProductAnalyticDto>> fetchProducts({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticProducts,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final products = ProductAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

  Future<DC<AnalyticFailure, PaymentMethodAnalyticDto>> fetchPaymentMethod({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticPaymentMethods,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final paymentMethods = PaymentMethodAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

  Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticProfitLoss,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final profitLoss = ProfitLossAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

  Future<DC<AnalyticFailure, CategoryAnalyticDto>> fetchCategories({
    required DateTime dateFrom,
    required DateTime dateTo,
  }) async {
    try {
      final response = await _apiClient.get(
        ApiPath.analyticCategories,
        params: {
          'date_from': dateFrom.toServerDate(),
          'date_to': dateTo.toServerDate(),
        },
        headers: getAuthorizationHeader(),
      );

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final categories = CategoryAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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

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

      if (response.data['success'] == false) {
        return DC.error(const AnalyticFailure.unexpectedError());
      }

      final inventory = InventoryAnalyticDto.fromJson(
        response.data['data'] as Map<String, dynamic>,
      );

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