import 'package:money2/money2.dart';

import 'package:flutter/material.dart';

import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/models/payment/settlement_mode.dart';
import 'package:pshared/provider/payment/amount.dart';
import 'package:pshared/utils/currency.dart';

import 'package:pweb/models/payment/amount/mode.dart';


class PaymentAmountFieldController extends ChangeNotifier {
  static const String _settlementCurrencyCode = 'RUB';

  final TextEditingController textController;
  final FocusNode focusNode = FocusNode();

  PaymentAmountProvider? _provider;
  PaymentSourceController? _source;
  bool _isSyncingText = false;
  PaymentAmountMode _mode = PaymentAmountMode.debit;

  PaymentAmountFieldController({required double? initialAmount})
    : textController = TextEditingController(
        text: initialAmount == null ? '' : initialAmount.toString(),
      );

  PaymentAmountMode get mode => _mode;
  bool get isReverseModeAvailable {
    final sourceCurrencyCode = _sourceCurrencyCode;
    return sourceCurrencyCode != null &&
        sourceCurrencyCode != _settlementCurrencyCode;
  }

  String? get activeCurrencyCode => switch (_mode) {
    PaymentAmountMode.debit => _sourceCurrencyCode,
    PaymentAmountMode.settlement => _settlementCurrencyCode,
  };

  void update(PaymentAmountProvider provider, PaymentSourceController source) {
    if (!identical(_provider, provider)) {
      _provider?.removeListener(_handleProviderChanged);
      _provider = provider;
      _provider?.addListener(_handleProviderChanged);
      _syncModeWithProvider(provider);
    }

    if (!identical(_source, source)) {
      _source?.removeListener(_handleSourceChanged);
      _source = source;
      _source?.addListener(_handleSourceChanged);
      _normalizeModeForSource();
    }

    _syncTextWithAmount(provider.amount);
  }

  void handleChanged(String value) {
    if (_isSyncingText) return;
    final parsed = _parseAmount(value);
    _provider?.setAmount(parsed);
  }

  void handleModeChanged(PaymentAmountMode value) {
    if (value == _mode) return;
    if (!isReverseModeAvailable && value == PaymentAmountMode.settlement) {
      return;
    }

    _mode = value;
    _provider?.setSettlementMode(_settlementModeFromMode(value));
    notifyListeners();
  }

  void _handleProviderChanged() {
    final provider = _provider;
    if (provider == null) return;
    _syncTextWithAmount(provider.amount);
    final changed = _syncModeWithProvider(provider);
    if (changed) {
      _normalizeModeForSource();
      notifyListeners();
    }
  }

  void _handleSourceChanged() {
    _normalizeModeForSource();
    notifyListeners();
  }

  bool _syncModeWithProvider(PaymentAmountProvider provider) {
    final nextMode = _modeFromSettlementMode(provider.settlementMode);
    if (nextMode == _mode) return false;
    _mode = nextMode;
    return true;
  }

  bool _normalizeModeForSource() {
    if (isReverseModeAvailable || _mode != PaymentAmountMode.settlement) {
      return false;
    }
    _mode = PaymentAmountMode.debit;
    _provider?.setSettlementMode(SettlementMode.fixSource);
    return true;
  }

  String? get _sourceCurrencyCode {
    return _source?.selectedCurrencyCode;
  }

  PaymentAmountMode _modeFromSettlementMode(SettlementMode mode) =>
      switch (mode) {
        SettlementMode.fixReceived => PaymentAmountMode.settlement,
        SettlementMode.fixSource ||
        SettlementMode.unspecified => PaymentAmountMode.debit,
      };

  SettlementMode _settlementModeFromMode(PaymentAmountMode mode) =>
      switch (mode) {
        PaymentAmountMode.debit => SettlementMode.fixSource,
        PaymentAmountMode.settlement => SettlementMode.fixReceived,
      };

  double? _parseAmount(String value) {
    return double.tryParse(value.replaceAll(',', '.').trim());
  }

  void _syncTextWithAmount(double? amount) {
    final parsedText = _parseAmount(textController.text);
    if (parsedText == amount) return;

    final nextText = amount == null ? '' : _formatAmount(amount);
    _isSyncingText = true;
    textController.value = TextEditingValue(
      text: nextText,
      selection: TextSelection.collapsed(offset: nextText.length),
    );
    _isSyncingText = false;
  }

  String _formatAmount(double amount) {
    final currency = money2CurrencyFromCode(activeCurrencyCode);
    if (currency == null) return amount.toString();
    return Money.fromNumWithCurrency(amount, currency).toDecimal().toString();
  }

  @override
  void dispose() {
    _provider?.removeListener(_handleProviderChanged);
    _source?.removeListener(_handleSourceChanged);
    focusNode.dispose();
    textController.dispose();
    super.dispose();
  }
}
