/// Domain Entity: Payment Line
///
/// Represents a payment transaction for an invoice.
library;

/// Payment method enum
enum PaymentMethod {
  /// Cash payment
  cash,

  /// Bank transfer
  bankTransfer,

  /// Credit card
  creditCard,

  /// E-wallet (Momo, ZaloPay, etc.)
  ewallet,

  /// Check
  check,

  /// Other method
  other;

  /// Get display name for payment method
  String get displayName {
    switch (this) {
      case PaymentMethod.cash:
        return 'Cash';
      case PaymentMethod.bankTransfer:
        return 'Bank Transfer';
      case PaymentMethod.creditCard:
        return 'Credit Card';
      case PaymentMethod.ewallet:
        return 'E-Wallet';
      case PaymentMethod.check:
        return 'Check';
      case PaymentMethod.other:
        return 'Other';
    }
  }
}

/// Payment status enum
enum PaymentStatus {
  /// Payment pending
  pending,

  /// Payment is being processed
  processing,

  /// Payment completed successfully
  completed,

  /// Payment failed
  failed,

  /// Payment refunded
  refunded,

  /// Payment cancelled
  cancelled;

  /// Get display name for status
  String get displayName {
    switch (this) {
      case PaymentStatus.pending:
        return 'Pending';
      case PaymentStatus.processing:
        return 'Processing';
      case PaymentStatus.completed:
        return 'Completed';
      case PaymentStatus.failed:
        return 'Failed';
      case PaymentStatus.refunded:
        return 'Refunded';
      case PaymentStatus.cancelled:
        return 'Cancelled';
    }
  }
}

/// Payment Line Entity
///
/// Contains payment transaction information:
/// - Payment details
/// - Payment method
/// - Bank information
/// - Status tracking
class PaymentLine {
  /// Unique payment line identifier
  final String paymentLineId;

  /// Invoice ID this payment is for
  final String invoiceId;

  /// Payment number (human-readable)
  final String paymentNumber;

  /// Payment date
  final DateTime paymentDate;

  /// Payment amount
  final double amount;

  /// Payment method
  final PaymentMethod paymentMethod;

  /// Bank name (for bank transfer)
  final String? bankName;

  /// Bank account number (for bank transfer)
  final String? bankAccount;

  /// Reference number (transaction ID, check number, etc.)
  final String? referenceNumber;

  /// Payment notes
  final String? notes;

  /// Payment status
  final PaymentStatus status;

  /// Receipt URL
  final String? receiptUrl;

  /// ERPNext payment entry reference
  final String? erpnextPaymentEntry;

  /// Creation timestamp
  final DateTime createdAt;

  /// Processing timestamp
  final DateTime? processedAt;

  const PaymentLine({
    required this.paymentLineId,
    required this.invoiceId,
    required this.paymentNumber,
    required this.paymentDate,
    required this.amount,
    required this.paymentMethod,
    this.bankName,
    this.bankAccount,
    this.referenceNumber,
    this.notes,
    required this.status,
    this.receiptUrl,
    this.erpnextPaymentEntry,
    required this.createdAt,
    this.processedAt,
  });

  /// Check if payment is completed
  bool get isCompleted => status == PaymentStatus.completed;

  /// Check if payment is pending
  bool get isPending => status == PaymentStatus.pending;

  /// Check if payment is being processed
  bool get isProcessing => status == PaymentStatus.processing;

  /// Check if payment failed
  bool get isFailed => status == PaymentStatus.failed;

  /// Check if payment has receipt
  bool get hasReceipt => receiptUrl != null && receiptUrl!.isNotEmpty;

  /// Copy with method for immutability
  PaymentLine copyWith({
    String? paymentLineId,
    String? invoiceId,
    String? paymentNumber,
    DateTime? paymentDate,
    double? amount,
    PaymentMethod? paymentMethod,
    String? bankName,
    String? bankAccount,
    String? referenceNumber,
    String? notes,
    PaymentStatus? status,
    String? receiptUrl,
    String? erpnextPaymentEntry,
    DateTime? createdAt,
    DateTime? processedAt,
  }) {
    return PaymentLine(
      paymentLineId: paymentLineId ?? this.paymentLineId,
      invoiceId: invoiceId ?? this.invoiceId,
      paymentNumber: paymentNumber ?? this.paymentNumber,
      paymentDate: paymentDate ?? this.paymentDate,
      amount: amount ?? this.amount,
      paymentMethod: paymentMethod ?? this.paymentMethod,
      bankName: bankName ?? this.bankName,
      bankAccount: bankAccount ?? this.bankAccount,
      referenceNumber: referenceNumber ?? this.referenceNumber,
      notes: notes ?? this.notes,
      status: status ?? this.status,
      receiptUrl: receiptUrl ?? this.receiptUrl,
      erpnextPaymentEntry: erpnextPaymentEntry ?? this.erpnextPaymentEntry,
      createdAt: createdAt ?? this.createdAt,
      processedAt: processedAt ?? this.processedAt,
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is PaymentLine &&
        other.paymentLineId == paymentLineId &&
        other.invoiceId == invoiceId &&
        other.paymentNumber == paymentNumber &&
        other.amount == amount &&
        other.paymentMethod == paymentMethod &&
        other.status == status;
  }

  @override
  int get hashCode {
    return Object.hash(
      paymentLineId,
      invoiceId,
      paymentNumber,
      amount,
      paymentMethod,
      status,
    );
  }

  @override
  String toString() {
    return 'PaymentLine(paymentLineId: $paymentLineId, paymentNumber: $paymentNumber, '
        'amount: $amount, paymentMethod: $paymentMethod, status: $status)';
  }
}
