/* 
 * This file is part of Stack Wallet.
 * 
 * Copyright (c) 2023 Cypher Stack
 * All Rights Reserved.
 * The code is distributed under GPLv3 license, see LICENSE file for details.
 * Generated by Cypher Stack on 2023-05-26
 *
 */

import 'package:decimal/decimal.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/exchange/active_pair.dart';
import '../../models/exchange/response_objects/estimate.dart';
import '../../models/exchange/response_objects/range.dart';
import '../global/locale_provider.dart';
import '../../services/exchange/exchange.dart';
import '../../services/exchange/exchange_response.dart';
import '../../utilities/amount/amount.dart';
import '../../utilities/amount/amount_unit.dart';

import '../../utilities/enums/exchange_rate_type_enum.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
import 'package:tuple/tuple.dart';

final efEstimatesListProvider = StateProvider.family<
    Tuple2<ExchangeResponse<List<Estimate>>, Range?>?,
    String>((ref, exchangeName) => null);

final efRateTypeProvider =
    StateProvider<ExchangeRateType>((ref) => ExchangeRateType.estimated);

final efExchangeProvider =
    StateProvider<Exchange>((ref) => Exchange.defaultExchange);
final efExchangeProviderNameProvider =
    StateProvider<String>((ref) => Exchange.defaultExchange.name);

final currentCombinedExchangeIdProvider = Provider<String>((ref) {
  return "${ref.watch(efExchangeProvider).name}"
      " (${ref.watch(efExchangeProviderNameProvider)})";
});

final efSendAmountProvider = StateProvider<Decimal?>((ref) => null);
final efReceiveAmountProvider = StateProvider<Decimal?>((ref) => null);

final efSendAmountStringProvider = StateProvider<String>((ref) {
  final refreshing = ref.watch(efRefreshingProvider);
  final reversed = ref.watch(efReversedProvider);
  if (refreshing && reversed) {
    return "-";
  } else {
    final decimal = ref.watch(efSendAmountProvider);
    String string = "";
    if (decimal != null) {
      final amount = Amount.fromDecimal(decimal, fractionDigits: decimal.scale);
      final locale = ref.watch(localeServiceChangeNotifierProvider).locale;
      string = AmountUnit.normal.displayAmount(
        amount: amount,
        locale: locale,
        coin: Nano(
          CryptoCurrencyNetwork.main,
        ), // use nano just to ensure decimal.scale < Coin.value.decimals
        withUnitName: false,
        maxDecimalPlaces: decimal.scale,
      );
    }

    return string;
  }
});
final efReceiveAmountStringProvider = StateProvider<String>((ref) {
  final refreshing = ref.watch(efRefreshingProvider);
  final reversed = ref.watch(efReversedProvider);

  if (refreshing && reversed == false) {
    return "-";
  } else {
    final decimal = ref.watch(efReceiveAmountProvider);
    String string = "";
    if (decimal != null) {
      final amount = Amount.fromDecimal(decimal, fractionDigits: decimal.scale);
      final locale = ref.watch(localeServiceChangeNotifierProvider).locale;
      string = AmountUnit.normal.displayAmount(
        amount: amount,
        locale: locale,
        coin: Nano(
          CryptoCurrencyNetwork.main,
        ), // use nano just to ensure decimal.scale < Coin.value.decimals
        withUnitName: false,
        maxDecimalPlaces: decimal.scale,
      );
    }

    return string;
  }
});

final efReversedProvider = StateProvider<bool>((ref) => false);

final efCurrencyPairProvider = ChangeNotifierProvider<ActivePair>(
  (ref) => ActivePair(),
);

final efEstimateProvider = StateProvider<Estimate?>((ref) {
  final exchange = ref.watch(efExchangeProvider);
  final provider = ref.watch(efExchangeProviderNameProvider);
  final reversed = ref.watch(efReversedProvider);
  final fixedRate = ref.watch(efRateTypeProvider) == ExchangeRateType.fixed;

  final matches = ref
      .watch(efEstimatesListProvider(exchange.name))
      ?.item1
      .value
      ?.where((e) {
    return e.exchangeProvider == provider &&
        e.fixedRate == fixedRate &&
        e.reversed == reversed;
  });

  Estimate? result;

  if (matches != null && matches.isNotEmpty) {
    result = matches.first;
  } else {
    result = null;
  }

  return result;
});

final efCanExchangeProvider = StateProvider<bool>((ref) {
  final Estimate? estimate = ref.watch(efEstimateProvider);
  final refreshing = ref.watch(efRefreshingProvider);

  return !refreshing && estimate != null;
});

final efRefreshingProvider = StateProvider<bool>((ref) => false);