/* 
 * 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 'dart:async';
import 'dart:io';

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

import '../../app_config.dart';
import '../../models/exchange/response_objects/trade.dart';
import '../../pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart';
import '../../providers/providers.dart';
import '../../route_generator.dart';
import '../../themes/coin_icon_provider.dart';
import '../../themes/stack_colors.dart';
import '../../themes/theme_providers.dart';
import '../../utilities/amount/amount.dart';
import '../../utilities/amount/amount_formatter.dart';
import '../../utilities/assets.dart';
import '../../utilities/constants.dart';
import '../../utilities/enums/fee_rate_type_enum.dart';
import '../../utilities/logger.dart';
import '../../utilities/text_styles.dart';
import '../../utilities/util.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
import '../../wallets/isar/providers/wallet_info_provider.dart';
import '../../wallets/models/tx_data.dart';
import '../../wallets/wallet/impl/firo_wallet.dart';
import '../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../widgets/background.dart';
import '../../widgets/conditional_parent.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../widgets/desktop/desktop_dialog.dart';
import '../../widgets/desktop/desktop_dialog_close_button.dart';
import '../../widgets/expandable.dart';
import '../../widgets/rounded_white_container.dart';
import '../../widgets/stack_dialog.dart';
import '../home_view/home_view.dart';
import '../send_view/sub_widgets/building_transaction_dialog.dart';
import 'confirm_change_now_send.dart';

class SendFromView extends ConsumerStatefulWidget {
  const SendFromView({
    super.key,
    required this.coin,
    required this.trade,
    required this.amount,
    required this.address,
    this.shouldPopRoot = false,
    this.fromDesktopStep4 = false,
  });

  static const String routeName = "/sendFrom";

  final CryptoCurrency coin;
  final Amount amount;
  final String address;
  final Trade trade;
  final bool shouldPopRoot;
  final bool fromDesktopStep4;

  @override
  ConsumerState<SendFromView> createState() => _SendFromViewState();
}

class _SendFromViewState extends ConsumerState<SendFromView> {
  late final CryptoCurrency coin;
  late final Amount amount;
  late final String address;
  late final Trade trade;

  @override
  void initState() {
    coin = widget.coin;
    address = widget.address;
    amount = widget.amount;
    trade = widget.trade;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    debugPrint("BUILD: $runtimeType");

    final walletIds = ref
        .watch(pWallets)
        .wallets
        .where((e) => e.info.coin == coin)
        .map((e) => e.walletId)
        .toList();

    final isDesktop = Util.isDesktop;

    return ConditionalParent(
      condition: !isDesktop,
      builder: (child) {
        return Background(
          child: Scaffold(
            backgroundColor:
                Theme.of(context).extension<StackColors>()!.background,
            appBar: AppBar(
              leading: AppBarBackButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
              title: Text(
                "Send from",
                style: STextStyles.navBarTitle(context),
              ),
            ),
            body: Padding(
              padding: const EdgeInsets.all(16),
              child: child,
            ),
          ),
        );
      },
      child: ConditionalParent(
        condition: isDesktop,
        builder: (child) => DesktopDialog(
          maxHeight: double.infinity,
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(
                      left: 32,
                    ),
                    child: Text(
                      "Send from ${AppConfig.prefix}",
                      style: STextStyles.desktopH3(context),
                    ),
                  ),
                  DesktopDialogCloseButton(
                    onPressedOverride: Navigator.of(
                      context,
                      rootNavigator: widget.shouldPopRoot,
                    ).pop,
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.only(
                  left: 32,
                  right: 32,
                  bottom: 32,
                ),
                child: child,
              ),
            ],
          ),
        ),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Row(
              children: [
                Text(
                  "You need to send ${ref.watch(pAmountFormatter(coin)).format(amount)}",
                  style: isDesktop
                      ? STextStyles.desktopTextExtraExtraSmall(context)
                      : STextStyles.itemSubtitle(context),
                ),
              ],
            ),
            const SizedBox(
              height: 16,
            ),
            ConditionalParent(
              condition: !isDesktop,
              builder: (child) => Expanded(
                child: child,
              ),
              child: ListView.builder(
                primary: isDesktop ? false : null,
                shrinkWrap: isDesktop,
                itemCount: walletIds.length,
                itemBuilder: (context, index) {
                  return Padding(
                    padding: const EdgeInsets.symmetric(vertical: 4),
                    child: SendFromCard(
                      walletId: walletIds[index],
                      amount: amount,
                      address: address,
                      trade: trade,
                      fromDesktopStep4: widget.fromDesktopStep4,
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class SendFromCard extends ConsumerStatefulWidget {
  const SendFromCard({
    super.key,
    required this.walletId,
    required this.amount,
    required this.address,
    required this.trade,
    this.fromDesktopStep4 = false,
  });

  final String walletId;
  final Amount amount;
  final String address;
  final Trade trade;
  final bool fromDesktopStep4;

  @override
  ConsumerState<SendFromCard> createState() => _SendFromCardState();
}

class _SendFromCardState extends ConsumerState<SendFromCard> {
  late final String walletId;
  late final Amount amount;
  late final String address;
  late final Trade trade;

  Future<void> _send({bool? shouldSendPublicFiroFunds}) async {
    final coin = ref.read(pWalletCoin(walletId));

    try {
      bool wasCancelled = false;

      final wallet = ref.read(pWallets).getWallet(walletId);

      unawaited(
        showDialog<dynamic>(
          context: context,
          useSafeArea: false,
          barrierDismissible: false,
          builder: (context) {
            return ConditionalParent(
              condition: Util.isDesktop,
              builder: (child) => DesktopDialog(
                maxWidth: 400,
                maxHeight: double.infinity,
                child: Padding(
                  padding: const EdgeInsets.all(32),
                  child: child,
                ),
              ),
              child: BuildingTransactionDialog(
                coin: coin,
                isSpark:
                    wallet is FiroWallet && shouldSendPublicFiroFunds != true,
                onCancel: () {
                  wasCancelled = true;

                  Navigator.of(context).pop();
                },
              ),
            );
          },
        ),
      );

      // Currently CwBasedInterface wallets (xmr/wow) shouldn't even have
      // access to this screen but this is needed to get past an error that
      // would occur only to lead to another error which is why xmr/wow wallets
      // don't have access to this screen currently
      if (wallet is LibMoneroWallet) {
        await wallet.init();
        await wallet.open();
      }

      final time = Future<dynamic>.delayed(
        const Duration(
          milliseconds: 2500,
        ),
      );

      TxData txData;
      Future<TxData> txDataFuture;

      // if not firo then do normal send
      if (shouldSendPublicFiroFunds == null) {
        final memo = coin is Stellar
            ? trade.payInExtraId.isNotEmpty
                ? trade.payInExtraId
                : null
            : null;
        txDataFuture = wallet.prepareSend(
          txData: TxData(
            recipients: [
              (
                address: address,
                amount: amount,
                isChange: false,
              ),
            ],
            memo: memo,
            feeRateType: FeeRateType.average,
          ),
        );
      } else {
        final firoWallet = wallet as FiroWallet;
        // otherwise do firo send based on balance selected
        if (shouldSendPublicFiroFunds) {
          txDataFuture = wallet.prepareSend(
            txData: TxData(
              recipients: [
                (
                  address: address,
                  amount: amount,
                  isChange: false,
                ),
              ],
              feeRateType: FeeRateType.average,
            ),
          );
        } else {
          txDataFuture = firoWallet.prepareSendSpark(
            txData: TxData(
              recipients: [
                (
                  address: address,
                  amount: amount,
                  isChange: false,
                ),
              ],
              // feeRateType: FeeRateType.average,
            ),
          );
        }
      }

      final results = await Future.wait([
        txDataFuture,
        time,
      ]);

      txData = results.first as TxData;

      if (!wasCancelled) {
        // pop building dialog

        if (mounted) {
          Navigator.of(
            context,
            rootNavigator: Util.isDesktop,
          ).pop();
        }

        txData = txData.copyWith(
          note: "${trade.payInCurrency.toUpperCase()}/"
              "${trade.payOutCurrency.toUpperCase()} exchange",
        );

        if (mounted) {
          await Navigator.of(context).push(
            RouteGenerator.getRoute(
              shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
              builder: (_) => ConfirmChangeNowSendView(
                txData: txData,
                walletId: walletId,
                routeOnSuccessName: Util.isDesktop
                    ? DesktopExchangeView.routeName
                    : HomeView.routeName,
                trade: trade,
                shouldSendPublicFiroFunds: shouldSendPublicFiroFunds,
                fromDesktopStep4: widget.fromDesktopStep4,
              ),
              settings: const RouteSettings(
                name: ConfirmChangeNowSendView.routeName,
              ),
            ),
          );
        }
      }
    } catch (e, s) {
      Logging.instance.log("$e\n$s", level: LogLevel.Error);
      if (mounted) {
        // pop building dialog
        Navigator.of(context).pop();

        await showDialog<dynamic>(
          context: context,
          useSafeArea: false,
          barrierDismissible: true,
          builder: (context) {
            return StackDialog(
              title: "Transaction failed",
              message: e.toString(),
              rightButton: TextButton(
                style: Theme.of(context)
                    .extension<StackColors>()!
                    .getSecondaryEnabledButtonStyle(context),
                child: Text(
                  "Ok",
                  style: STextStyles.button(context).copyWith(
                    color: Theme.of(context)
                        .extension<StackColors>()!
                        .buttonTextSecondary,
                  ),
                ),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            );
          },
        );
      }
    }
  }

  @override
  void initState() {
    walletId = widget.walletId;
    amount = widget.amount;
    address = widget.address;
    trade = widget.trade;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final wallet = ref.watch(pWallets).getWallet(walletId);

    final locale = ref.watch(
      localeServiceChangeNotifierProvider.select((value) => value.locale),
    );

    final coin = ref.watch(pWalletCoin(walletId));

    final isFiro = coin is Firo;

    return RoundedWhiteContainer(
      padding: const EdgeInsets.all(0),
      child: ConditionalParent(
        condition: isFiro,
        builder: (child) => Expandable(
          header: Container(
            color: Colors.transparent,
            child: Padding(
              padding: const EdgeInsets.all(12),
              child: child,
            ),
          ),
          body: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              MaterialButton(
                splashColor:
                    Theme.of(context).extension<StackColors>()!.highlight,
                key: Key("walletsSheetItemButtonFiroPrivateKey_$walletId"),
                padding: const EdgeInsets.all(0),
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(
                    Constants.size.circularBorderRadius,
                  ),
                ),
                onPressed: () async {
                  if (mounted) {
                    unawaited(
                      _send(
                        shouldSendPublicFiroFunds: false,
                      ),
                    );
                  }
                },
                child: Container(
                  color: Colors.transparent,
                  child: Padding(
                    padding: const EdgeInsets.only(
                      top: 6,
                      left: 16,
                      right: 16,
                      bottom: 6,
                    ),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              "Use private balance",
                              style: STextStyles.itemSubtitle(context),
                            ),
                            Text(
                              ref.watch(pAmountFormatter(coin)).format(
                                    ref
                                        .watch(pWalletBalanceTertiary(walletId))
                                        .spendable,
                                  ),
                              style: STextStyles.itemSubtitle(context),
                            ),
                          ],
                        ),
                        SvgPicture.asset(
                          Assets.svg.chevronRight,
                          height: 14,
                          width: 7,
                          color: Theme.of(context)
                              .extension<StackColors>()!
                              .infoItemLabel,
                        ),
                      ],
                    ),
                  ),
                ),
              ),
              MaterialButton(
                splashColor:
                    Theme.of(context).extension<StackColors>()!.highlight,
                key: Key("walletsSheetItemButtonFiroPublicKey_$walletId"),
                padding: const EdgeInsets.all(0),
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(
                    Constants.size.circularBorderRadius,
                  ),
                ),
                onPressed: () async {
                  if (mounted) {
                    unawaited(
                      _send(
                        shouldSendPublicFiroFunds: true,
                      ),
                    );
                  }
                },
                child: Container(
                  color: Colors.transparent,
                  child: Padding(
                    padding: const EdgeInsets.only(
                      top: 6,
                      left: 16,
                      right: 16,
                      bottom: 6,
                    ),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              "Use public balance",
                              style: STextStyles.itemSubtitle(context),
                            ),
                            Text(
                              ref.watch(pAmountFormatter(coin)).format(
                                    ref
                                        .watch(pWalletBalance(walletId))
                                        .spendable,
                                  ),
                              style: STextStyles.itemSubtitle(context),
                            ),
                          ],
                        ),
                        SvgPicture.asset(
                          Assets.svg.chevronRight,
                          height: 14,
                          width: 7,
                          color: Theme.of(context)
                              .extension<StackColors>()!
                              .infoItemLabel,
                        ),
                      ],
                    ),
                  ),
                ),
              ),
              const SizedBox(
                height: 6,
              ),
            ],
          ),
        ),
        child: ConditionalParent(
          condition: !isFiro,
          builder: (child) => MaterialButton(
            splashColor: Theme.of(context).extension<StackColors>()!.highlight,
            key: Key("walletsSheetItemButtonKey_$walletId"),
            padding: const EdgeInsets.all(8),
            materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(
                Constants.size.circularBorderRadius,
              ),
            ),
            onPressed: () async {
              if (mounted) {
                unawaited(
                  _send(),
                );
              }
            },
            child: child,
          ),
          child: Row(
            children: [
              Container(
                decoration: BoxDecoration(
                  color: ref.watch(pCoinColor(coin)).withOpacity(0.5),
                  borderRadius: BorderRadius.circular(
                    Constants.size.circularBorderRadius,
                  ),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(6),
                  child: SvgPicture.file(
                    File(
                      ref.watch(
                        coinIconProvider(coin),
                      ),
                    ),
                    width: 24,
                    height: 24,
                  ),
                ),
              ),
              const SizedBox(
                width: 12,
              ),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      ref.watch(pWalletName(walletId)),
                      style: STextStyles.titleBold12(context),
                    ),
                    if (!isFiro)
                      const SizedBox(
                        height: 2,
                      ),
                    if (!isFiro)
                      Text(
                        ref.watch(pAmountFormatter(coin)).format(
                              ref.watch(pWalletBalance(walletId)).spendable,
                            ),
                        style: STextStyles.itemSubtitle(context),
                      ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}