import 'package:pshared/models/payment/operation_document.dart';
import 'package:pshared/models/payment/operation.dart';
import 'package:pshared/models/payment/payment.dart';
import 'package:pshared/models/payment/state.dart';
import 'package:pshared/models/payment/status.dart';

import 'package:pweb/utils/payment/upload_metadata.dart';
import 'package:pweb/utils/report/operations/document_rule.dart';


OperationItem mapPaymentToOperation(Payment payment) {
  final debit = payment.lastQuote?.amounts?.sourceDebitTotal;
  final settlement = payment.lastQuote?.amounts?.destinationSettlement;
  final amountMoney = debit ?? settlement;

  final amount = amountMoney?.toDouble() ?? 0;
  final currency = amountMoney?.currency.isoCode ?? '';
  final toAmount = settlement == null
      ? amount
      : settlement.toDouble();
  final toCurrency = settlement?.currency.isoCode ?? currency;

  final payId = _firstNonEmpty([payment.paymentRef]) ?? '-';
  final name =
      _firstNonEmpty([payment.lastQuote?.quoteRef, payment.paymentRef]) ?? '-';
  // final comment =
  //     _firstNonEmpty([
  //       ...payment.operations.map((operation) => operation.comment),
  //       payment.comment,
  //       payment.failureReason,
  //       payment.failureCode,
  //       payment.state,
  //     ]) ??
  //     '';
  final operationDocument = _resolveOperationDocument(payment);

  return OperationItem(
    status: statusFromPayment(payment),
    fileName: _extractFileName(payment.metadata),
    amount: amount,
    currency: currency,
    toAmount: toAmount,
    toCurrency: toCurrency,
    payId: payId,
    paymentRef: payment.paymentRef,
    operationRef: operationDocument?.operationRef,
    gatewayService: operationDocument?.gatewayService,
    cardNumber: null,
    name: name,
    date: resolvePaymentDate(payment),
    // comment: comment,
  );
}

OperationDocumentRef? _resolveOperationDocument(Payment payment) {
  for (final operation in payment.operations) {
    final operationRef = operation.operationRef;
    final gatewayService = operation.gateway;
    if (operationRef == null || operationRef.isEmpty) continue;
    if (gatewayService == null || gatewayService.isEmpty) continue;

    if (!isOperationDocumentEligible(operation.code)) continue;

    return OperationDocumentRef(
      operationRef: operationRef,
      gatewayService: gatewayService,
    );
  }
  return null;
}

OperationStatus statusFromPayment(Payment payment) {
  switch (payment.orchestrationState) {
    case PaymentOrchestrationState.failed:
      return OperationStatus.error;
    case PaymentOrchestrationState.settled:
      return OperationStatus.success;
    case PaymentOrchestrationState.needsAttention:
      return OperationStatus.needsAttention;
    case PaymentOrchestrationState.created:
      return OperationStatus.pending;
    case PaymentOrchestrationState.executing:
      return OperationStatus.processing;
    case PaymentOrchestrationState.unspecified:
      return OperationStatus.pending;
  }
}

DateTime resolvePaymentDate(Payment payment) {
  final createdAt = payment.createdAt;
  if (createdAt != null) return createdAt.toLocal();

  final expiresAt = payment.lastQuote?.fxQuote?.expiresAtUnixMs;
  if (expiresAt != null && expiresAt > 0) {
    return DateTime.fromMillisecondsSinceEpoch(
      expiresAt,
      isUtc: true,
    ).toLocal();
  }

  return DateTime.fromMillisecondsSinceEpoch(0);
}

String? paymentIdFromOperation(OperationItem operation) {
  final candidates = [operation.paymentRef, operation.payId];
  for (final candidate in candidates) {
    final trimmed = candidate?.trim();
    if (trimmed != null && trimmed.isNotEmpty && trimmed != '-') {
      return trimmed;
    }
  }
  return null;
}

String? _extractFileName(Map<String, String>? metadata) {
  if (metadata == null || metadata.isEmpty) return null;
  return _firstNonEmpty([
    metadata[UploadMetadataKeys.fileName],
    metadata[UploadMetadataKeys.legacyFileName],
    metadata[UploadMetadataKeys.fallbackFileName],
  ]);
}

String? _firstNonEmpty(List<String?> values) {
  for (final value in values) {
    final trimmed = value?.trim();
    if (trimmed != null && trimmed.isNotEmpty) return trimmed;
  }
  return null;
}
