import 'package:money2/money2.dart';

import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/models/payment/asset.dart';
import 'package:pshared/models/payment/chain_network.dart';
import 'package:pshared/models/payment/customer.dart';
import 'package:pshared/models/payment/currency_pair.dart';
import 'package:pshared/models/payment/fees/treatment.dart';
import 'package:pshared/models/payment/fx/intent.dart';
import 'package:pshared/models/payment/fx/side.dart';
import 'package:pshared/models/payment/kind.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/ledger.dart';
import 'package:pshared/models/payment/methods/managed_wallet.dart';
import 'package:pshared/models/payment/methods/type.dart';
import 'package:pshared/models/payment/settlement_mode.dart';
import 'package:pshared/models/payment/intent.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/payment/amount.dart';
import 'package:pshared/provider/payment/flow.dart';
import 'package:pshared/provider/recipient/provider.dart';
import 'package:pshared/utils/currency.dart';
import 'package:pshared/utils/payment/fx_helpers.dart';


class QuotationIntentBuilder {
  static const String _settlementCurrency = 'RUB';

  PaymentIntent? build({
    required PaymentAmountProvider payment,
    required PaymentSourceController source,
    required PaymentFlowProvider flow,
    required RecipientsProvider recipients,
  }) {
    final sourceMethod = _resolveSourceMethod(source);
    final sourceCurrency = source.selectedCurrencyCode;
    final paymentData = flow.selectedPaymentData;
    final selectedMethod = flow.selectedMethod;
    final amountValue = payment.amount;
    if (sourceCurrency == null) {
      return null;
    }

    final customer = _buildCustomer(
      recipient: recipients.currentObject,
      method: selectedMethod,
      data: paymentData,
    );
    final amountCurrency = payment.settlementMode == SettlementMode.fixReceived
        ? _settlementCurrency
        : sourceCurrency;
    final currency = money2CurrencyFromCode(amountCurrency);
    if (currency == null) return null;
    final amount = amountValue == null
        ? null
        : Money.fromNumWithCurrency(amountValue, currency);
    final isLedgerSource = source.selectedLedgerAccount != null;
    final isCryptoToCrypto =
        paymentData is CryptoAddressPaymentMethod &&
        (paymentData.asset?.tokenSymbol ?? '').trim().toUpperCase() ==
            sourceCurrency.trim().toUpperCase();
    final fxIntent = _buildFxIntent(
      sourceCurrency: sourceCurrency,
      settlementMode: payment.settlementMode,
      isLedgerSource: isLedgerSource,
      enabled: !isCryptoToCrypto,
    );
    return PaymentIntent(
      kind: PaymentKind.payout,
      amount: amount,
      destination: paymentData,
      source: sourceMethod,
      fx: fxIntent,
      feeTreatment: payment.payerCoversFee
          ? FeeTreatment.addToSource
          : FeeTreatment.deductFromDestination,
      settlementMode: payment.settlementMode,
      comment: payment.comment,
      customer: customer,
    );
  }

  FxIntent? _buildFxIntent({
    required String sourceCurrency,
    required SettlementMode settlementMode,
    required bool isLedgerSource,
    required bool enabled,
  }) {
    if (!enabled) return null;

    // Ledger sources in fix_received mode need explicit reverse side.
    // BFF maps only settlement currency + fx side, then quotation derives pair.
    // For ledger this preserves source debit in ledger currency (e.g. USDT).
    if (isLedgerSource && settlementMode == SettlementMode.fixReceived) {
      return FxIntent(
        pair: CurrencyPair(base: sourceCurrency, quote: _settlementCurrency),
        side: FxSide.buyBaseSellQuote,
      );
    }

    return FxIntentHelper.buildSellBaseBuyQuote(
      baseCurrency: sourceCurrency,
      quoteCurrency: _settlementCurrency, // TODO: exentd target currencies
      enabled: true,
    );
  }

  PaymentMethodData? _resolveSourceMethod(PaymentSourceController source) {
    final wallet = source.selectedWallet;
    if (wallet != null) {
      return ManagedWalletPaymentMethod(
        managedWalletRef: wallet.id,
        asset: PaymentAsset(
          tokenSymbol: wallet.tokenSymbol ?? '',
          chain: wallet.network ?? ChainNetwork.unspecified,
        ),
      );
    }

    final ledger = source.selectedLedgerAccount;
    if (ledger != null) {
      return LedgerPaymentMethod(ledgerAccountRef: ledger.ledgerAccountRef);
    }

    return null;
  }

  Customer? _buildCustomer({
    required Recipient? recipient,
    required PaymentMethod? method,
    required PaymentMethodData? data,
  }) {
    final customerId = recipient?.id.trim() ?? '';
    final card = _resolveCard(method: method, data: data);
    final fromRecipient = _buildCustomerFromName(
      customerId: customerId,
      fullName: recipient?.name,
      country: card?.country,
    );
    if (fromRecipient != null) return fromRecipient;

    if (card != null) {
      final firstName = _normalizedOrNull(card.firstName);
      final lastName = _normalizedOrNull(card.lastName);
      if (firstName == null && lastName == null) return null;
      return Customer(
        id: customerId,
        firstName: firstName,
        lastName: lastName,
        country: card.country,
      );
    }
    return null;
  }

  CardPaymentMethod? _resolveCard({
    required PaymentMethod? method,
    required PaymentMethodData? data,
  }) => method?.cardData ?? (data is CardPaymentMethod ? data : null);

  Customer? _buildCustomerFromName({
    required String customerId,
    required String? fullName,
    String? country,
  }) {
    final normalizedName = _normalizedOrNull(fullName);
    if (normalizedName == null) return null;
    final parts = normalizedName.split(RegExp(r'\s+'));
    final firstName = parts.isNotEmpty ? parts.first : null;
    final lastName = parts.length >= 2 ? parts.last : null;
    final middleName = parts.length > 2
        ? parts.sublist(1, parts.length - 1).join(' ')
        : null;
    return Customer(
      id: customerId,
      firstName: firstName,
      middleName: middleName,
      lastName: lastName,
      country: country,
    );
  }

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