/* 
 * This file is part of Stack Wallet.
 * 
 * Copyright (c) 2023 Cypher Stack
 * All Rights Reserved.
 * The code is distributed under GPLv3 license, see LICENSE file for details.
 * Generated by Cypher Stack on 2023-05-26
 *
 */

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart';

import '../../app_config.dart';
import '../../models/add_wallet_list_entity/sub_classes/coin_entity.dart';
import '../../models/isar/models/ethereum/eth_contract.dart';
import '../../pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart';
import '../../providers/db/main_db_provider.dart';
import '../../providers/providers.dart';
import '../../services/event_bus/events/wallet_added_event.dart';
import '../../services/event_bus/global_event_bus.dart';
import '../../themes/stack_colors.dart';
import '../../utilities/assets.dart';
import '../../utilities/constants.dart';
import '../../utilities/text_styles.dart';
import '../../utilities/util.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
import '../../wallets/isar/models/wallet_info.dart';
import '../../wallets/isar/providers/wallet_info_provider.dart';
import '../../wallets/wallet/wallet.dart';
import '../../widgets/background.dart';
import '../../widgets/conditional_parent.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../widgets/icon_widgets/x_icon.dart';
import '../../widgets/master_wallet_card.dart';
import '../../widgets/rounded_white_container.dart';
import '../../widgets/stack_text_field.dart';
import '../../widgets/textfield_icon_button.dart';
import '../../widgets/wallet_card.dart';
import '../add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';

class WalletsOverview extends ConsumerStatefulWidget {
  const WalletsOverview({
    super.key,
    required this.coin,
    this.navigatorState,
    this.overrideSimpleWalletCardPopPreviousValueWith,
  });

  final CryptoCurrency coin;
  final NavigatorState? navigatorState;
  final bool? overrideSimpleWalletCardPopPreviousValueWith;

  static const routeName = "/walletsOverview";

  @override
  ConsumerState<WalletsOverview> createState() => _EthWalletsOverviewState();
}

typedef WalletListItemData = ({Wallet wallet, List<EthContract> contracts});

class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> {
  final isDesktop = Util.isDesktop;

  late final TextEditingController _searchController;
  late final FocusNode searchFieldFocusNode;

  String _searchString = "";

  final Map<String, WalletListItemData> wallets = {};

  List<WalletListItemData> _filter(String searchTerm) {
    // clean out deleted wallets
    final existingWalletIds = ref
        .read(mainDBProvider)
        .isar
        .walletInfo
        .where()
        .walletIdProperty()
        .findAllSync();
    wallets.removeWhere((k, v) => !existingWalletIds.contains(k));

    if (searchTerm.isEmpty) {
      return wallets.values.toList()
        ..sort((a, b) => a.wallet.info.name.compareTo(b.wallet.info.name));
    }

    final Map<String, WalletListItemData> results = {};
    final term = searchTerm.toLowerCase();

    for (final entry in wallets.entries) {
      bool includeManager = false;
      // search wallet name and total balance
      includeManager |= _elementContains(entry.value.wallet.info.name, term);
      includeManager |= _elementContains(
        entry.value.wallet.info.cachedBalance.total.decimal.toString(),
        term,
      );

      final List<EthContract> contracts = [];

      for (final contract in entry.value.contracts) {
        if (_elementContains(contract.name, term)) {
          contracts.add(contract);
        } else if (_elementContains(contract.symbol, term)) {
          contracts.add(contract);
        } else if (_elementContains(contract.type.name, term)) {
          contracts.add(contract);
        } else if (_elementContains(contract.address, term)) {
          contracts.add(contract);
        }
      }

      if (includeManager || contracts.isNotEmpty) {
        results.addEntries([entry]);
      }
    }

    return results.values.toList()
      ..sort((a, b) => a.wallet.info.name.compareTo(b.wallet.info.name));
  }

  bool _elementContains(String element, String term) {
    return element.toLowerCase().contains(term);
  }

  void updateWallets() {
    final walletsData =
        ref.read(mainDBProvider).isar.walletInfo.where().findAllSync();
    walletsData.removeWhere((e) => e.coin != widget.coin);

    if (widget.coin is Ethereum) {
      for (final data in walletsData) {
        final List<EthContract> contracts = [];
        final contractAddresses =
            ref.read(pWalletTokenAddresses(data.walletId));

        // fetch each contract
        for (final contractAddress in contractAddresses) {
          final contract = ref
              .read(
                mainDBProvider,
              )
              .getEthContractSync(
                contractAddress,
              );

          // add it to list if it exists in DB
          if (contract != null) {
            contracts.add(contract);
          }
        }

        // add tuple to list
        wallets[data.walletId] = (
          wallet: ref.read(pWallets).getWallet(
                data.walletId,
              ),
          contracts: contracts,
        );
      }
    } else {
      // add non token wallet tuple to list
      for (final data in walletsData) {
        // desktop single coin apps may cause issues so lets just ignore the error and move on
        try {
          wallets[data.walletId] = (
            wallet: ref.read(pWallets).getWallet(
                  data.walletId,
                ),
            contracts: [],
          );
        } catch (_) {
          // lol bandaid for single coin based apps
        }
      }
    }
  }

  @override
  void initState() {
    _searchController = TextEditingController();
    searchFieldFocusNode = FocusNode();

    updateWallets();

    if (AppConfig.isSingleCoinApp) {
      GlobalEventBus.instance.on<WalletAddedEvent>().listen((_) {
        updateWallets();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (mounted) {
            setState(() {});
          }
        });
      });
    }

    super.initState();
  }

  @override
  void dispose() {
    _searchController.dispose();
    searchFieldFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ConditionalParent(
      condition: !isDesktop && !AppConfig.isSingleCoinApp,
      builder: (child) => Background(
        child: Scaffold(
          backgroundColor:
              Theme.of(context).extension<StackColors>()!.background,
          appBar: AppBar(
            leading: const AppBarBackButton(),
            title: Text(
              "${widget.coin.prettyName} (${widget.coin.ticker}) wallets",
              style: STextStyles.navBarTitle(context),
            ),
            actions: [
              AspectRatio(
                aspectRatio: 1,
                child: AppBarIconButton(
                  icon: SvgPicture.asset(
                    Assets.svg.plus,
                    width: 18,
                    height: 18,
                    color: Theme.of(context)
                        .extension<StackColors>()!
                        .topNavIconPrimary,
                  ),
                  onPressed: () {
                    Navigator.of(context).pushNamed(
                      CreateOrRestoreWalletView.routeName,
                      arguments: CoinEntity(widget.coin),
                    );
                  },
                ),
              ),
            ],
          ),
          body: SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: child,
            ),
          ),
        ),
      ),
      child: Column(
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(
              Constants.size.circularBorderRadius,
            ),
            child: TextField(
              autocorrect: !isDesktop,
              enableSuggestions: !isDesktop,
              controller: _searchController,
              focusNode: searchFieldFocusNode,
              onChanged: (value) {
                setState(() {
                  _searchString = value;
                });
              },
              style: isDesktop
                  ? STextStyles.desktopTextExtraSmall(context).copyWith(
                      color: Theme.of(context)
                          .extension<StackColors>()!
                          .textFieldActiveText,
                      height: 1.8,
                    )
                  : STextStyles.field(context),
              decoration: standardInputDecoration(
                "Search...",
                searchFieldFocusNode,
                context,
                desktopMed: isDesktop,
              ).copyWith(
                prefixIcon: Padding(
                  padding: EdgeInsets.symmetric(
                    horizontal: isDesktop ? 12 : 10,
                    vertical: isDesktop ? 18 : 16,
                  ),
                  child: SvgPicture.asset(
                    Assets.svg.search,
                    width: isDesktop ? 20 : 16,
                    height: isDesktop ? 20 : 16,
                  ),
                ),
                suffixIcon: _searchController.text.isNotEmpty
                    ? Padding(
                        padding: const EdgeInsets.only(right: 0),
                        child: UnconstrainedBox(
                          child: Row(
                            children: [
                              TextFieldIconButton(
                                child: const XIcon(),
                                onTap: () async {
                                  setState(() {
                                    _searchController.text = "";
                                    _searchString = "";
                                  });
                                },
                              ),
                            ],
                          ),
                        ),
                      )
                    : null,
              ),
            ),
          ),
          const SizedBox(
            height: 16,
          ),
          Expanded(
            child: Builder(
              builder: (context) {
                final data = _filter(_searchString);
                return ListView.separated(
                  itemBuilder: (_, index) {
                    final entry = data[index];
                    final wallet = entry.wallet;

                    if (wallet.cryptoCurrency.hasTokenSupport) {
                      if (isDesktop) {
                        return DesktopExpandingWalletCard(
                          key: Key(
                            "${wallet.walletId}_${entry.contracts.map((e) => e.address).join()}",
                          ),
                          data: entry,
                          navigatorState: widget.navigatorState!,
                        );
                      } else {
                        return MasterWalletCard(
                          key: Key(wallet.walletId),
                          walletId: wallet.walletId,
                        );
                      }
                    } else {
                      return ConditionalParent(
                        key: Key(wallet.walletId),
                        condition: isDesktop,
                        builder: (child) => RoundedWhiteContainer(
                          padding: const EdgeInsets.symmetric(
                            vertical: 14,
                            horizontal: 20,
                          ),
                          borderColor: Theme.of(context)
                              .extension<StackColors>()!
                              .backgroundAppBar,
                          child: child,
                        ),
                        child: SimpleWalletCard(
                          walletId: wallet.walletId,
                          popPrevious: widget
                                      .overrideSimpleWalletCardPopPreviousValueWith ==
                                  null
                              ? isDesktop
                              : widget
                                  .overrideSimpleWalletCardPopPreviousValueWith!,
                          desktopNavigatorState:
                              isDesktop ? widget.navigatorState : null,
                        ),
                      );
                    }
                  },
                  separatorBuilder: (_, __) => SizedBox(
                    height: isDesktop ? 10 : 8,
                  ),
                  itemCount: data.length,
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}