import 'package:flutter/widgets.dart';

import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/provider/ledger.dart';

import 'package:pweb/models/dashboard/balance_item.dart';
import 'package:pweb/pages/dashboard/buttons/balance/config.dart';


class BalanceCarouselController extends ChangeNotifier {
  BalanceCarouselController()
    : pageController = PageController(
        viewportFraction: WalletCardConfig.viewportFraction,
      );

  WalletsController? _walletsController;
  List<BalanceItem> _items = const <BalanceItem>[BalanceItem.addAction()];
  int _index = 0;
  final PageController pageController;

  List<BalanceItem> get items => _items;
  int get index => _index;

  void update({
    required WalletsController walletsController,
    required LedgerAccountsProvider ledgerProvider,
  }) {
    _walletsController = walletsController;

    final nextItems = <BalanceItem>[
      ...walletsController.wallets.map(BalanceItem.wallet),
      ...ledgerProvider.accounts.map(BalanceItem.ledger),
      const BalanceItem.addAction(),
    ];

    final nextIndex = _resolveNextIndex(nextItems, walletsController);
    final hasItemsChanged = !_isSameItems(_items, nextItems);
    final hasIndexChanged = _index != nextIndex;

    _items = nextItems;
    _index = nextIndex;
    _syncPageController();

    if (hasItemsChanged || hasIndexChanged) {
      notifyListeners();
    }
  }

  void onPageChanged(int value) {
    final next = _clampIndex(value, _items.length);
    if (_index == next) {
      _syncSelectedWallet();
      return;
    }

    _index = next;
    _syncSelectedWallet();
    notifyListeners();
  }

  void goBack() => animateTo(_index - 1);

  void goForward() => animateTo(_index + 1);

  void animateTo(int index) {
    final target = _clampIndex(index, _items.length);
    if (!pageController.hasClients) {
      onPageChanged(target);
      return;
    }
    pageController.animateToPage(
      target,
      duration: const Duration(milliseconds: 220),
      curve: Curves.easeOut,
    );
  }

  void syncPageController() => _syncPageController();

  int _resolveNextIndex(
    List<BalanceItem> nextItems,
    WalletsController walletsController,
  ) {
    final currentWalletRef = _currentWalletRef(_items, _index);
    if (currentWalletRef != null) {
      final byCurrentWallet = _walletIndexByRef(nextItems, currentWalletRef);
      if (byCurrentWallet != null) return byCurrentWallet;

      final selectedWalletRef = walletsController.selectedWalletRef;
      final bySelectedWallet = _walletIndexByRef(nextItems, selectedWalletRef);
      if (bySelectedWallet != null) return bySelectedWallet;
    }

    return _clampIndex(_index, nextItems.length);
  }

  String? _currentWalletRef(List<BalanceItem> items, int index) {
    if (items.isEmpty || index < 0 || index >= items.length) return null;
    final current = items[index];
    return switch (current) {
      WalletBalanceItem(:final wallet) => wallet.id,
      _ => null,
    };
  }

  int? _walletIndexByRef(List<BalanceItem> items, String? walletRef) {
    if (walletRef == null || walletRef.isEmpty) return null;
    final idx = items.indexWhere(
      (item) => switch (item) {
        WalletBalanceItem(:final wallet) => wallet.id == walletRef,
        _ => false,
      },
    );
    if (idx < 0) return null;
    return idx;
  }

  int _clampIndex(int value, int itemCount) {
    if (itemCount <= 0) return 0;
    return value.clamp(0, itemCount - 1);
  }

  bool _isSameItems(List<BalanceItem> left, List<BalanceItem> right) {
    if (left.length != right.length) return false;

    for (var i = 0; i < left.length; i++) {
      final a = left[i];
      final b = right[i];
      if (a.runtimeType != b.runtimeType) return false;
      if (_itemIdentity(a) != _itemIdentity(b)) return false;
    }

    return true;
  }

  String _itemIdentity(BalanceItem item) => switch (item) {
    WalletBalanceItem(:final wallet) => wallet.id,
    LedgerBalanceItem(:final account) => account.ledgerAccountRef,
    AddBalanceActionItem() => 'add',
  };

  void _syncSelectedWallet() {
    final walletsController = _walletsController;
    if (walletsController == null || _items.isEmpty) return;

    final current = _items[_index];
    if (current is! WalletBalanceItem) return;
    final wallet = current.wallet;
    if (walletsController.selectedWallet?.id == wallet.id) return;
    walletsController.selectWallet(wallet);
  }

  void _syncPageController() {
    if (!pageController.hasClients || _items.isEmpty) return;
    final current = pageController.page?.round();
    final target = _clampIndex(_index, _items.length);
    if (current == target) return;
    pageController.jumpToPage(target);
  }

  @override
  void dispose() {
    pageController.dispose();
    super.dispose();
  }
}
