import 'package:money2/money2.dart';

import 'package:pshared/models/payment/fees/line.dart';
import 'package:pshared/models/payment/quote/quote.dart';
import 'package:pshared/utils/currency.dart';


Money? quoteFeeTotal(PaymentQuote? quote) {
  return quoteFeeTotalFromLines(
    quote?.fees?.lines,
    preferredCurrency:
        quote?.amounts?.sourcePrincipal?.currency.isoCode ??
        quote?.amounts?.sourceDebitTotal?.currency.isoCode,
  );
}

Money? quoteSourceDebitTotal(
  PaymentQuote? quote, {
  String? preferredSourceCurrency,
}) {
  final sourceDebitTotal = quote?.amounts?.sourceDebitTotal;
  final preferredCurrency = _normalizeCurrency(
    preferredSourceCurrency ??
        quote?.amounts?.sourcePrincipal?.currency.isoCode,
  );

  if (sourceDebitTotal == null) {
    return _rebuildSourceDebitTotal(
      quote,
      preferredSourceCurrency: preferredCurrency,
    );
  }

  if (preferredCurrency == null ||
      _normalizeCurrency(sourceDebitTotal.currency.isoCode) ==
          preferredCurrency) {
    return sourceDebitTotal;
  }

  final rebuilt = _rebuildSourceDebitTotal(
    quote,
    preferredSourceCurrency: preferredCurrency,
  );
  return rebuilt ?? sourceDebitTotal;
}

Money? quoteFeeTotalFromLines(
  List<FeeLine>? lines, {
  String? preferredCurrency,
}) {
  if (lines == null || lines.isEmpty) return null;

  final normalizedPreferred = _normalizeCurrency(preferredCurrency);
  final totalsByCurrency = <String, Money>{};

  for (final line in lines) {
    final parsedAmount = line.amount;
    if (parsedAmount == null) continue;

    final currencyCode = parsedAmount.currency.isoCode;
    final signedAmount = _isCreditLine(line.side) ? -parsedAmount : parsedAmount;
    final current = totalsByCurrency[currencyCode];
    totalsByCurrency[currencyCode] = current == null
        ? signedAmount
        : current + signedAmount;
  }

  if (totalsByCurrency.isEmpty) return null;

  final selectedCurrency =
      normalizedPreferred != null &&
          totalsByCurrency.containsKey(normalizedPreferred)
      ? normalizedPreferred
      : totalsByCurrency.keys.first;
  return totalsByCurrency[selectedCurrency];
}

List<Money> aggregateMoneyByCurrency(Iterable<Money?> values) {
  final totals = <String, Money>{};
  for (final value in values) {
    if (value == null) continue;
    final currency = value.currency.isoCode;
    final current = totals[currency];
    totals[currency] = current == null ? value : current + value;
  }

  return totals.values.toList();
}

Money? _rebuildSourceDebitTotal(
  PaymentQuote? quote, {
  String? preferredSourceCurrency,
}) {
  final principal = quote?.amounts?.sourcePrincipal;
  if (principal == null) return null;

  final principalCurrency = principal.currency.isoCode;
  if (preferredSourceCurrency != null &&
      principalCurrency != preferredSourceCurrency) {
    return null;
  }

  var totalAmount = principal;
  final fee = quoteFeeTotalFromLines(
    quote?.fees?.lines,
    preferredCurrency: principalCurrency,
  );
  if (fee != null && fee.currency.isoCode == principalCurrency) {
    totalAmount += fee;
  }

  return totalAmount;
}

bool _isCreditLine(String? side) {
  final normalized = side?.trim().toLowerCase() ?? '';
  switch (normalized) {
    case 'entry_side_credit':
    case 'credit':
      return true;
    default:
      return false;
  }
}

String? _normalizeCurrency(String? currency) {
  final normalized = currency?.trim();
  if (normalized == null || normalized.isEmpty) return null;
  return money2CurrencyFromCode(normalized)?.isoCode ?? normalized.toUpperCase();
}
