"""Onchain Controller Module"""
__docformat__ = "numpy"

# pylint: disable=C0302

import argparse
import difflib
import logging
from datetime import datetime, timedelta
from typing import List, Optional

from openbb_terminal.core.session.current_user import get_current_user
from openbb_terminal.cryptocurrency.due_diligence.glassnode_model import (
    GLASSNODE_SUPPORTED_HASHRATE_ASSETS,
    INTERVALS_HASHRATE,
)
from openbb_terminal.cryptocurrency.due_diligence.glassnode_view import display_hashrate
from openbb_terminal.cryptocurrency.onchain import (
    bitquery_model,
    bitquery_view,
    blockchain_view,
    ethgasstation_view,
    ethplorer_model,
    ethplorer_view,
    shroom_view,
    whale_alert_model,
    whale_alert_view,
)
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import (
    EXPORT_BOTH_RAW_DATA_AND_FIGURES,
    EXPORT_ONLY_RAW_DATA_ALLOWED,
    check_int_range,
    check_positive,
    valid_date,
)
from openbb_terminal.menu import session
from openbb_terminal.parent_classes import BaseController
from openbb_terminal.rich_config import MenuText, console

logger = logging.getLogger(__name__)


class OnchainController(BaseController):
    """Onchain Controller class"""

    SPECIFIC_CHOICES = {
        "account": [
            "balance",
            "hist",
        ],
        "token": [
            "info",
            "th",
            "prices",
            "holders",
        ],
        "tx": ["tx"],
    }

    CHOICES_COMMANDS = [
        "hr",
        "gwei",
        "whales",
        "balance",
        "top",
        "holders",
        "tx",
        "hist",
        "info",
        "th",
        "prices",
        "address",
        "lt",
        "dvcp",
        "tv",
        "ueat",
        "ttcp",
        "baas",
        "btccp",
        "btcct",
        "btcblockdata",
        "query",
    ]

    PATH = "/crypto/onchain/"
    CHOICES_GENERATION = True

    def __init__(self, queue: Optional[List[str]] = None):
        """Constructor"""
        super().__init__(queue)

        self.address = ""
        self.address_type = ""

        if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
            choices: dict = self.choices_default

            choices["hr"].update({c: {} for c in GLASSNODE_SUPPORTED_HASHRATE_ASSETS})

            self.completer = NestedCompleter.from_nested_dict(choices)

    def print_help(self):
        """Print help"""
        mt = MenuText("crypto/onchain/")
        mt.add_cmd("hr")
        mt.add_cmd("btccp")
        mt.add_cmd("btcct")
        mt.add_cmd("btcblockdata")
        mt.add_cmd("gwei")
        mt.add_cmd("whales")
        mt.add_cmd("lt")
        mt.add_cmd("dvcp")
        mt.add_cmd("tv")
        mt.add_cmd("ueat")
        mt.add_cmd("ttcp")
        mt.add_cmd("baas")
        mt.add_cmd("query")
        mt.add_raw("\n")
        mt.add_param("_address", self.address or "")
        mt.add_param("_type", self.address_type or "")
        mt.add_raw("\n")
        mt.add_info("_ethereum_")
        mt.add_cmd("address")
        mt.add_cmd("top")
        mt.add_cmd("balance", self.address_type == "account")
        mt.add_cmd("hist", self.address_type == "account")
        mt.add_cmd("info", self.address_type == "token")
        mt.add_cmd("holders", self.address_type == "token")
        mt.add_cmd("th", self.address_type == "token")
        mt.add_cmd("prices", self.address_type == "token")
        mt.add_cmd("tx", self.address_type == "tx")
        console.print(text=mt.menu_text, menu="Cryptocurrency - Onchain")

    @log_start_end(log=logger)
    def call_query(self, other_args: List[str]):
        """Process query command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="query",
            description="""
                Make any flipsidecrypto query
                [Source:https://docs.flipsidecrypto.com/]
            """,
        )

        parser.add_argument(
            "-q",
            "--query",
            dest="query",
            type=str,
            nargs="+",
            required=not any(["-h" in other_args, "--help" in other_args]),
            help="Query to make",
        )

        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "-q")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES, limit=10
        )

        if ns_parser:
            shroom_view.display_query(
                query=" ".join(ns_parser.query),
                export=ns_parser.export,
                limit=ns_parser.limit,
            )

    @log_start_end(log=logger)
    def call_btcct(self, other_args: List[str]):
        """Process btcct command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="btcct",
            description="""
                Display BTC confirmed transactions [Source: https://api.blockchain.info/]
            """,
        )

        parser.add_argument(
            "-s",
            "--since",
            dest="since",
            type=valid_date,
            help="Initial date. Default: 2010-01-01",
            default=datetime(2010, 1, 1).strftime("%Y-%m-%d"),
        )

        parser.add_argument(
            "-u",
            "--until",
            dest="until",
            type=valid_date,
            help=f"Final date. Default: {(datetime.now()).strftime('%Y-%m-%d')}",
            default=(datetime.now()).strftime("%Y-%m-%d"),
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES
        )

        if ns_parser:
            blockchain_view.display_btc_confirmed_transactions(
                start_date=ns_parser.since.strftime("%Y-%m-%d"),
                end_date=ns_parser.until.strftime("%Y-%m-%d"),
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_btccp(self, other_args: List[str]):
        """Process btccp command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="btccp",
            description="""
                Display BTC circulating supply [Source: https://api.blockchain.info/]
            """,
        )

        parser.add_argument(
            "-s",
            "--since",
            dest="since",
            type=valid_date,
            help="Initial date. Default: 2010-01-01",
            default=datetime(2010, 1, 1).strftime("%Y-%m-%d"),
        )

        parser.add_argument(
            "-u",
            "--until",
            dest="until",
            type=valid_date,
            help="Final date. Default: 2021-01-01",
            default=(datetime.now()).strftime("%Y-%m-%d"),
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES
        )

        if ns_parser:
            blockchain_view.display_btc_circulating_supply(
                start_date=ns_parser.since.strftime("%Y-%m-%d"),
                end_date=ns_parser.until.strftime("%Y-%m-%d"),
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_hr(self, other_args: List[str]):
        """Process hr command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="hr",
            description="""
                Display mean hashrate for a certain blockchain (ETH or BTC)
                [Source: https://glassnode.org]
            """,
        )

        parser.add_argument(
            "-c",
            "--coin",
            dest="coin",
            type=str,
            help="Coin to check hashrate (BTC or ETH)",
            default="BTC",
            choices=GLASSNODE_SUPPORTED_HASHRATE_ASSETS,
        )

        parser.add_argument(
            "-i",
            "--interval",
            dest="interval",
            type=str,
            help="Frequency interval. Default: 24h",
            default="24h",
            choices=INTERVALS_HASHRATE,
        )

        parser.add_argument(
            "-s",
            "--since",
            dest="since",
            type=valid_date,
            help=f"Initial date. Default: {(datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')}",
            default=(datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
        )

        parser.add_argument(
            "-u",
            "--until",
            dest="until",
            type=valid_date,
            help=f"Final date. Default: {(datetime.now()).strftime('%Y-%m-%d')}",
            default=(datetime.now()).strftime("%Y-%m-%d"),
        )

        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "-c")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES
        )

        if ns_parser:
            display_hashrate(
                symbol=ns_parser.coin,
                interval=ns_parser.interval,
                start_date=ns_parser.since.strftime("%Y-%m-%d"),
                end_date=ns_parser.until.strftime("%Y-%m-%d"),
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_gwei(self, other_args: List[str]):
        """Process gwei command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="onchain",
            description="""
                Display ETH gas fees
                [Source: https://ethgasstation.info]
            """,
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            ethgasstation_view.display_gwei_fees(
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_whales(self, other_args: List[str]):
        """Process whales command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="whales",
            description="""
                Display crypto whales transactions.
                [Source: https://docs.whale-alert.io/]
            """,
        )

        parser.add_argument(
            "-m",
            "--min",
            dest="min",
            type=check_int_range(500000, 100**7),
            help="Minimum value of transactions.",
            default=1000000,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: date",
            default="date",
            choices=whale_alert_model.FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        parser.add_argument(
            "-a",
            "--address",
            dest="address",
            action="store_true",
            help="Flag to show addresses of transaction",
            default=False,
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            whale_alert_view.display_whales_transactions(
                min_value=ns_parser.min,
                limit=ns_parser.limit,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                show_address=ns_parser.address,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_address(self, other_args: List[str]):
        """Process address command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="address",
            description="""
                Load address for further analysis. You can analyze account address, token address or transaction hash.
                [Source: Ethplorer]
            """,
        )

        parser.add_argument(
            "-a",
            action="store_true",
            help="Account address",
            dest="account",
            default=False,
        )

        parser.add_argument(
            "-t",
            action="store_true",
            help="ERC20 token address",
            dest="token",
            default=False,
        )

        parser.add_argument(
            "-tx",
            action="store_true",
            help="Transaction hash",
            dest="transaction",
            default=False,
        )

        parser.add_argument(
            "--address",
            dest="address",
            help="Ethereum address",
            default=False,
            type=str,
            required="-h" not in other_args,
        )

        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "--address")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            if len(ns_parser.address) not in [42, 66]:
                console.print(
                    f"Couldn't load address {ns_parser.address}. "
                    f"Token or account address should be 42 characters long. "
                    f"Transaction hash should be 66 characters long\n"
                )

            if ns_parser.account:
                address_type = "account"
            elif ns_parser.token:
                address_type = "token"
            elif ns_parser.transaction:
                address_type = "tx"
            else:
                address_type = "account"

            if len(ns_parser.address) == 66:
                address_type = "tx"

            self.address = ns_parser.address
            self.address_type = address_type

    @log_start_end(log=logger)
    def call_balance(self, other_args: List[str]):
        """Process balance command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="balance",
            description="""
                Display info about tokens on given ethereum blockchain balance.
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: index",
            default="index",
            choices=ethplorer_model.BALANCE_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            if self.address:
                ethplorer_view.display_address_info(
                    limit=ns_parser.limit,
                    sortby=ns_parser.sortby,
                    ascend=ns_parser.reverse,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_hist(self, other_args: List[str]):
        """Process hist command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="hist",
            description="""
                Display history for given ethereum blockchain balance.
                e.g. 0x3cD751E6b0078Be393132286c442345e5DC49699
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: timestamp",
            default="timestamp",
            choices=ethplorer_model.HIST_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            if self.address:
                ethplorer_view.display_address_history(
                    limit=ns_parser.limit,
                    sortby=ns_parser.sortby,
                    ascend=ns_parser.reverse,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_holders(self, other_args: List[str]):
        """Process holders command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="holders",
            description="""
                Display top ERC20 token holders: e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: share",
            default="share",
            choices=ethplorer_model.HOLDERS_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            if self.address:
                ethplorer_view.display_top_token_holders(
                    limit=ns_parser.limit,
                    sortby=ns_parser.sortby,
                    ascend=ns_parser.reverse,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_top(self, other_args: List[str]):
        """Process top command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="top",
            description="""
                Display top ERC20 tokens.
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: rank",
            default="rank",
            choices=ethplorer_model.TOP_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            ethplorer_view.display_top_tokens(
                limit=ns_parser.limit,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_info(self, other_args: List[str]):
        """Process info command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="info",
            description="""
                Display info about ERC20 token. e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
                [Source: Ethplorer]
            """,
        )

        parser.add_argument(
            "--social",
            action="store_false",
            help="Flag to show social media links",
            dest="social",
            default=False,
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            if self.address:
                ethplorer_view.display_token_info(
                    social=ns_parser.social,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_th(self, other_args: List[str]):
        """Process th command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="th",
            description="""
                Displays info about token history.
                e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: value",
            default="value",
            choices=ethplorer_model.TH_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        parser.add_argument(
            "--hash",
            action="store_false",
            help="Flag to show transaction hash",
            dest="hash",
            default=True,
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            if self.address:
                ethplorer_view.display_token_history(
                    limit=ns_parser.limit,
                    hash_=ns_parser.hash,
                    sortby=ns_parser.sortby,
                    ascend=ns_parser.reverse,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_tx(self, other_args: List[str]):
        """Process tx command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="tx",
            description="""
                Display info ERC20 token transaction on ethereum blockchain.
                e.g. 0x9dc7b43ad4288c624fdd236b2ecb9f2b81c93e706b2ffd1d19b112c1df7849e6
                [Source: Ethplorer]
            """,
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            if self.address:
                ethplorer_view.display_tx_info(
                    tx_hash=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_prices(self, other_args: List[str]):
        """Process prices command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="prices",
            description="""
                Display token historical prices. e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
                [Source: Ethplorer]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: date",
            default="date",
            choices=ethplorer_model.PRICES_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            if self.address:
                ethplorer_view.display_token_historical_prices(
                    limit=ns_parser.limit,
                    sortby=ns_parser.sortby,
                    ascend=ns_parser.reverse,
                    address=self.address,
                    export=ns_parser.export,
                    sheet_name=" ".join(ns_parser.sheet_name)
                    if ns_parser.sheet_name
                    else None,
                )
            else:
                console.print("You need to set an ethereum address\n")

    @log_start_end(log=logger)
    def call_lt(self, other_args: List[str]):
        """Process lt command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="lt",
            description="""
                Display Trades on Decentralized Exchanges aggregated by DEX or Month
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-k",
            "--kind",
            dest="kind",
            type=str,
            help="Aggregate trades by dex or time Default: dex",
            default="dex",
            choices=bitquery_model.LT_KIND,
        )
        parser.add_argument(
            "-vs",
            "--vs",
            dest="vs",
            type=str,
            help="Currency of displayed trade amount.",
            default="USD",
            choices=bitquery_model.CURRENCIES,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-d",
            "--days",
            dest="days",
            type=check_positive,
            help="Number of days to display data for.",
            default=90,
            choices=range(1, 360),
            metavar="DAYS",
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column. Default: tradeAmount. For monthly trades date.",
            default="tradeAmount",
            choices=bitquery_model.LT_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            bitquery_view.display_dex_trades(
                kind=ns_parser.kind,
                trade_amount_currency=ns_parser.vs,
                limit=ns_parser.limit,
                days=ns_parser.days,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_dvcp(self, other_args: List[str]):
        """Process dvcp command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="dvcp",
            description="""
                Display daily volume for given crypto pair
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-c",
            "--coin",
            dest="coin",
            type=str,
            help="ERC20 token symbol or address.",
            required="-h" not in other_args,
        )
        parser.add_argument(
            "-vs",
            "--vs",
            dest="vs",
            type=str,
            help="Quote currency",
            default="USDT",
            choices=bitquery_model.CURRENCIES,
        )
        parser.add_argument(
            "-d",
            "--days",
            dest="days",
            type=check_positive,
            help="Number of days to display data for.",
            default=10,
            choices=range(1, 100),
            metavar="DAYS",
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column.",
            default="date",
            choices=bitquery_model.DVCP_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "-c")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            bitquery_view.display_daily_volume_for_given_pair(
                symbol=ns_parser.coin,
                to_symbol=ns_parser.vs,
                limit=ns_parser.days,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_tv(self, other_args: List[str]):
        """Process tv command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="tv",
            description="""
                Display token volume on different Decentralized Exchanges.
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-c",
            "--coin",
            dest="coin",
            type=str,
            help="ERC20 token symbol or address.",
            required="-h" not in other_args,
        )
        parser.add_argument(
            "-vs",
            "--vs",
            dest="vs",
            type=str,
            help="Currency of displayed trade amount.",
            default="USD",
            choices=bitquery_model.CURRENCIES,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column.",
            default="trades",
            choices=bitquery_model.LT_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "-c")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            bitquery_view.display_dex_volume_for_token(
                symbol=ns_parser.coin,
                trade_amount_currency=ns_parser.vs,
                limit=ns_parser.limit,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_ueat(self, other_args: List[str]):
        """Process ueat command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="ueat",
            description="""
                Display number of unique ethereum addresses which made a transaction in given time interval,
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records. (Maximum available time period is 90 days."
            "Depending on chosen time period, display N records will be recalculated. E.g."
            "For interval: month, and number: 10, period of calculation equals to 300, "
            "but because of max days limit: 90, it will only return last 3 months (3 records). ",
            default=10,
            choices=range(1, 90),
            metavar="LIMIT",
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column.",
            default="date",
            choices=bitquery_model.UEAT_FILTERS,
        )
        parser.add_argument(
            "-i",
            "--interval",
            dest="interval",
            type=str,
            help="Time interval in which ethereum address made transaction. month, week or day. "
            "Maximum time period is 90 days (3 months, 14 weeks)",
            default="day",
            choices=bitquery_model.INTERVALS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        ns_parser = self.parse_known_args_and_warn(
            parser,
            other_args,
            EXPORT_ONLY_RAW_DATA_ALLOWED,
        )

        if ns_parser:
            bitquery_view.display_ethereum_unique_senders(
                interval=ns_parser.interval,
                limit=ns_parser.limit,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_ttcp(self, other_args: List[str]):
        """Process ttcp command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="ttcp",
            description="""
                Display most traded crypto pairs on given decentralized exchange in chosen time period.
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="display N number records",
            default=10,
        )
        parser.add_argument(
            "-e",
            "--exchange",
            dest="exchange",
            type=str,
            help="Decentralized exchange name.",
            choices=bitquery_model.DECENTRALIZED_EXCHANGES,
        )
        parser.add_argument(
            "-d",
            "--days",
            dest="days",
            type=check_positive,
            help="Number of days to display data for.",
            default=30,
            choices=range(1, 100),
            metavar="DAYS",
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column.",
            default="tradeAmount",
            choices=bitquery_model.TTCP_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        if other_args and "-" not in other_args[0][0]:
            other_args.insert(0, "-e")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            exchange = "Uniswap"
            if ns_parser.exchange:
                if ns_parser.exchange in bitquery_model.DECENTRALIZED_EXCHANGES:
                    exchange = ns_parser.exchange
                else:
                    similar_cmd = difflib.get_close_matches(
                        ns_parser.exchange,
                        bitquery_model.DECENTRALIZED_EXCHANGES,
                        n=1,
                        cutoff=0.75,
                    )

                    if similar_cmd:
                        console.print(f"Replacing by '{similar_cmd[0]}'")
                        exchange = similar_cmd[0]

                    else:
                        similar_cmd = difflib.get_close_matches(
                            ns_parser.exchange,
                            bitquery_model.DECENTRALIZED_EXCHANGES,
                            n=1,
                            cutoff=0.5,
                        )
                        if similar_cmd:
                            console.print(f"Did you mean '{similar_cmd[0]}'?")

                        console.print(
                            f"Couldn't find any exchange with provided name: {ns_parser.exchange}. "
                            f"Please choose one from list: {bitquery_model.DECENTRALIZED_EXCHANGES}\n"
                        )

            else:
                console.print("Exchange not provided setting default to Uniswap.\n")

            bitquery_view.display_most_traded_pairs(
                days=ns_parser.days,
                limit=ns_parser.limit,
                exchange=exchange,
                sortby=ns_parser.sortby,
                ascend=ns_parser.reverse,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )

    @log_start_end(log=logger)
    def call_baas(self, other_args: List[str]):
        """Process baas command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="baas",
            description="""
                Display average bid, ask prices, spread for given crypto pair for chosen time period
                [Source: https://graphql.bitquery.io/]
            """,
        )
        parser.add_argument(
            "-c",
            "--coin",
            dest="coin",
            type=str,
            help="ERC20 token symbol or address.",
            choices=bitquery_model.POSSIBLE_CRYPTOS,
            metavar="COIN",
        )
        parser.add_argument(
            "-vs",
            "--vs",
            dest="vs",
            type=str,
            help="Quote currency",
            default="USDT",
            choices=bitquery_model.CURRENCIES,
        )
        parser.add_argument(
            "-l",
            "--limit",
            dest="limit",
            type=check_positive,
            help="Number of days to display data for.",
            default=10,
        )
        parser.add_argument(
            "-s",
            "--sort",
            dest="sortby",
            type=str,
            help="Sort by given column.",
            default="date",
            choices=bitquery_model.BAAS_FILTERS,
        )
        parser.add_argument(
            "-r",
            "--reverse",
            action="store_true",
            dest="reverse",
            default=False,
            help=(
                "Data is sorted in descending order by default. "
                "Reverse flag will sort it in an ascending way. "
                "Only works when raw data is displayed."
            ),
        )
        if other_args and other_args[0][0] != "-":
            other_args.insert(0, "-c")

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )
        if ns_parser:
            if ns_parser.coin:
                if ns_parser.coin in bitquery_model.POSSIBLE_CRYPTOS:
                    bitquery_view.display_spread_for_crypto_pair(
                        symbol=ns_parser.coin,
                        to_symbol=ns_parser.vs,
                        limit=ns_parser.limit,
                        sortby=ns_parser.sortby,
                        ascend=ns_parser.reverse,
                        export=ns_parser.export,
                        sheet_name=" ".join(ns_parser.sheet_name)
                        if ns_parser.sheet_name
                        else None,
                    )

                else:
                    console.print(f"Coin '{ns_parser.coin}' does not exist.")
                    if ns_parser.coin.upper() == "BTC":
                        token = "WBTC"
                    else:
                        similar_cmd = difflib.get_close_matches(
                            ns_parser.coin,
                            bitquery_model.POSSIBLE_CRYPTOS,
                            n=1,
                            cutoff=0.75,
                        )
                        try:
                            token = similar_cmd[0]
                            if similar_cmd[0]:
                                console.print(f"Replacing with '{token}'")
                                bitquery_view.display_spread_for_crypto_pair(
                                    token=token,
                                    to_symbol=ns_parser.vs,
                                    limit=ns_parser.limit,
                                    sortby=ns_parser.sortby,
                                    ascend=ns_parser.reverse,
                                    export=ns_parser.export,
                                    sheet_name=" ".join(ns_parser.sheet_name)
                                    if ns_parser.sheet_name
                                    else None,
                                )
                        except Exception:
                            similar_cmd = difflib.get_close_matches(
                                ns_parser.coin,
                                bitquery_model.POSSIBLE_CRYPTOS,
                                n=1,
                                cutoff=0.5,
                            )
                            if similar_cmd:
                                console.print(f"Did you mean '{similar_cmd[0]}'?")

            else:
                console.print("You didn't provide coin symbol.\n")

    @log_start_end(log=logger)
    def call_btcblockdata(self, other_args: List[str]):
        """Process btcblockdata command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="btcblockdata",
            description="""
                Display block data from Blockchain.com,
                [Source: https://api.blockchain.info/]
            """,
        )

        if other_args and "-" not in other_args[0]:
            other_args.insert(0, "--blockhash")

        parser.add_argument(
            "--blockhash",
            action="store",
            help="Flag for block hash of block.",
            dest="blockhash",
            default=False,
        )

        ns_parser = self.parse_known_args_and_warn(
            parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
        )

        if ns_parser:
            blockchain_view.display_btc_single_block(
                blockhash=ns_parser.blockhash,
                export=ns_parser.export,
                sheet_name=" ".join(ns_parser.sheet_name)
                if ns_parser.sheet_name
                else None,
            )
