import 'package:pshared/models/describable.dart';
import 'package:pshared/models/payment/methods/card.dart';
import 'package:pshared/models/payment/methods/crypto_address.dart';
import 'package:pshared/models/payment/methods/data.dart';
import 'package:pshared/models/payment/methods/iban.dart';
import 'package:pshared/models/payment/methods/ledger.dart';
import 'package:pshared/models/payment/methods/managed_wallet.dart';
import 'package:pshared/models/payment/methods/russian_bank.dart';
import 'package:pshared/models/payment/methods/wallet.dart';
import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/permissions/bound.dart';
import 'package:pshared/models/permissions/bound/storable.dart';
import 'package:pshared/models/storable.dart';


class PaymentMethod implements PermissionBoundStorable, Describable {
  final Storable storable;
  final PermissionBound permissionBound;
  final Describable describable;
  final String recipientRef;
  final PaymentMethodData data;
  final bool isArchived;
  final bool isMain;

  const PaymentMethod({
    required this.storable,
    required this.permissionBound,
    required this.describable,
    required this.recipientRef,
    required this.data,
    this.isArchived = false,
    this.isMain = false,
  });

  PaymentType get type => data.type;

  T dataAs<T extends PaymentMethodData>() {
    final currentData = data;
    if (currentData is T) return currentData;
    throw StateError('Payment method data is ${currentData.runtimeType}, requested $T for type $type');
  }
  T? dataAsOrNull<T extends PaymentMethodData>() => data is T ? data as T : null;

  CardPaymentMethod? get cardData => dataAsOrNull<CardPaymentMethod>();
  IbanPaymentMethod? get ibanData => dataAsOrNull<IbanPaymentMethod>();
  RussianBankAccountPaymentMethod? get bankAccountData => dataAsOrNull<RussianBankAccountPaymentMethod>();
  WalletPaymentMethod? get walletData => dataAsOrNull<WalletPaymentMethod>();
  ManagedWalletPaymentMethod? get managedWalletData => dataAsOrNull<ManagedWalletPaymentMethod>();
  CryptoAddressPaymentMethod? get cryptoAddressData => dataAsOrNull<CryptoAddressPaymentMethod>();
  LedgerPaymentMethod? get ledgerData => dataAsOrNull<LedgerPaymentMethod>();

  @override
  String get id => storable.id;
  @override
  DateTime get createdAt => storable.createdAt;
  @override
  DateTime get updatedAt => storable.updatedAt;

  @override
  String get organizationRef => permissionBound.organizationRef;
  @override
  String get permissionRef => permissionBound.permissionRef;

  @override
  String get name => describable.name;
  @override
  String? get description => describable.description;

  PaymentMethod copyWith({
    PaymentMethodData? data,
    bool? isArchived,
    bool? isMain,
    Describable? describable,
  }) => PaymentMethod(
    storable: storable,
    permissionBound: permissionBound,
    recipientRef: recipientRef,
    data: data ?? this.data,
    isArchived: isArchived ?? this.isArchived,
    isMain: isMain ?? this.isMain,
    describable: describable ?? this.describable,
  );
}
