import 'package:pshared/models/payment/endpoint.dart';
import 'package:pshared/models/payment/methods/data.dart';
import 'package:pshared/models/payment/methods/ledger.dart';
import 'package:pshared/models/payment/methods/managed_wallet.dart';
import 'package:pshared/models/payment/methods/wallet.dart';
import 'package:pshared/models/payment/payment.dart';
import 'package:pshared/models/payment/source_type.dart';


typedef _SourceRefExtractor = String? Function(PaymentMethodData source);

final Map<PaymentSourceType, _SourceRefExtractor> _sourceExtractors = {
  PaymentSourceType.wallet: _walletSourceRef,
  PaymentSourceType.ledger: _ledgerSourceRef,
};

bool paymentMatchesSource(
  Payment payment, {
  required PaymentSourceType sourceType,
  required String sourceRef,
}) {
  final normalizedSourceRef = _normalize(sourceRef);
  if (normalizedSourceRef == null) return false;

  final paymentSourceRefs = _paymentSourceRefs(payment, sourceType);
  if (paymentSourceRefs.isEmpty) return false;

  return paymentSourceRefs.contains(normalizedSourceRef);
}

Set<String> _paymentSourceRefs(Payment payment, PaymentSourceType sourceType) {
  final fromSource = _sourceRefsFromEndpoint(payment.source, sourceType);
  if (fromSource.isEmpty) return const <String>{};
  return fromSource;
}

Set<String> _sourceRefsFromEndpoint(
  PaymentEndpoint? endpoint,
  PaymentSourceType sourceType,
) {
  if (endpoint == null) return const <String>{};

  final refs = <String>{};
  void collect(String? value) {
    final normalized = _normalize(value);
    if (normalized == null) return;
    refs.add(normalized);
  }

  final source = endpoint.method;
  if (source != null) {
    final fromMethod = _sourceExtractors[sourceType]?.call(source);
    collect(fromMethod);
  }

  collect(endpoint.paymentMethodRef);

  return refs;
}

String? _walletSourceRef(PaymentMethodData source) => switch (source) {
  ManagedWalletPaymentMethod(:final managedWalletRef) => _normalize(
    managedWalletRef,
  ),
  WalletPaymentMethod(:final walletId) => _normalize(walletId),
  _ => null,
};

String? _ledgerSourceRef(PaymentMethodData source) => switch (source) {
  LedgerPaymentMethod(:final ledgerAccountRef) => _normalize(ledgerAccountRef),
  _ => null,
};

String? _normalize(String? value) {
  final normalized = value?.trim();
  if (normalized == null || normalized.isEmpty) return null;
  return normalized;
}
