#   . documentação API: https://docs.coingecko.com/v3.0.1/reference/introduction

import requests
from typing import Any
from modulos.constantes import CHAVE_API_DEMO

headers = {"accept": "application/json", "x-cg-demo-api-key": CHAVE_API_DEMO}

url_raiz_API = "https://api.coingecko.com/api/v3/"

# chamada API geral


def API(
    api_endpoint: str = "", api_params_dict: dict[str, str] = {}
) -> tuple[str, int, dict[Any, Any]]:
    """função genérica para fazer uma chamada a API CoinGecko"""
    # validar parametros
    # api_endpoint
    if not isinstance(api_endpoint, str):
        raise TypeError("'api_endpoint' tem de ser do tipo 'str'")
    if api_endpoint is None or api_endpoint == "":
        raise ValueError("'api_endpoint' tem de ser definido")
    # api_params_dict
    if not isinstance(api_params_dict, dict):
        raise TypeError("'api_params_dict' tem de ser do tipo 'dict'")

    # processar argumentos
    api_params_string = "" if api_params_dict == {} else "?"
    ampersand = ""  # primeira iteração é '', depois passa a '&'
    for param in api_params_dict:
        if api_params_dict[param] == "":
            continue
        api_params_string += ampersand + param + "=" + api_params_dict[param]
        if ampersand == "":
            ampersand = "&"
    url_pedido = url_raiz_API + api_endpoint + api_params_string
    resposta = requests.get(url_pedido, headers=headers)
    # log to url do pedido
    # print(f"URL: {url_pedido}")
    return url_pedido, resposta.status_code, resposta.json()


def ping() -> tuple[str, int, dict]:
    """https://docs.coingecko.com/v3.0.1/reference/ping-server

    função para verificar o estado do servidor API CoinGecko"""
    return API("ping", {})


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = ping()
# print(f'codigo: {codigo}')
# print(f'resposta: {dados}')


def coin_price_by_ids(
    ids: str = "",
    vs_currencies: str = "",
    include_market_cap: bool = False,
    include_24hr_vol: bool = False,
    include_24hr_change: bool = False,
    include_last_updated_at: bool = False,
    precision: int | str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/simple-price

    consultar preço de um ou mais moedas usando o seu ID de Moeda

    podem ser passadas multiplas IDs de moedas separadas por virgula,
    como objecto de tipo 'str'

    parametros:
        ids (obrigatorio)

        vs_currencies (obrigatorio)"""
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "ids": "",
        "vs_currencies": "",
        "include_24hr_vol": "",
        "include_24hr_change": "",
        "include_last_update_at": "",
        "precision": "",
    }
    # validacao de parametros
    # ids
    if not isinstance(ids, str):
        raise TypeError("'ids' não é do tipo 'str'")
    if ids == "":
        raise ValueError("'ids' tem de ser definido")
    api_parameters["ids"] = ids
    # vs_currencies
    if not isinstance(vs_currencies, str):
        raise TypeError("'vs_currencies' não é do tipo 'str'")
    if vs_currencies == "":
        raise ValueError("'vs_currencies' tem de ser definido")
    api_parameters["vs_currencies"] = vs_currencies
    # include_market_cap
    if not isinstance(include_market_cap, bool):
        include_market_cap = False
    if include_market_cap:
        api_parameters["include_market_cap"] = str(True).lower()
    # include_24hr_vol
    if not isinstance(include_24hr_vol, bool):
        include_24hr_vol = False
    if include_24hr_vol:
        api_parameters["include_24hr_vol"] = str(True).lower()
    # include_24hr_change
    if not isinstance(include_24hr_change, bool):
        include_24hr_change = False
    if include_24hr_change:
        api_parameters["include_24hr_change"] = str(True).lower()
    # include_last_update_at
    if not isinstance(include_last_updated_at, bool):
        include_last_updated_at = False
    if include_last_updated_at:
        api_parameters["include_last_updated_at"] = str(True).lower()
    # precision
    if not isinstance(precision, (int, str)):
        raise TypeError("'precision' não é do tipo 'int' ou 'str'")
    if precision != "":
        if isinstance(precision, str):
            if precision == "full":
                precision = "18"
            precision = int(precision)
        if isinstance(precision, int):
            if precision < 0:
                precision = 0
            if precision > 18:
                precision = 18
            precision = str(precision)
        api_parameters["precision"] = precision

    return API("simple/price", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados_dict = coin_price_by_ids('bitcoin,xkc,ethereum','eur', precision=True)
# print(f'url: {url}')
# if codigo == 200:
#     for moeda in dados_dict:
#         print(f'{moeda}')
#         for vs_currencies in dados_dict[moeda]:
#             print(f'\t{vs_currencies}: {dados_dict[moeda][vs_currencies]}')
# else:
#     print(f'erro: {codigo}{dados_dict}')


def coin_price_by_token_addresses(
    id_platform: str = "",
    contract_addresses: str = "",
    vs_currencies: str = "",
    include_market_cap: bool = False,
    include_24hr_vol: bool = False,
    include_24hr_change: bool = False,
    include_last_updated_at: bool = False,
    precision: int | str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/simple-token-price

    consultar preco de tokens usando os endereços de contrato dos tokens

    parametros:
        id (obrigatorio) - id da plataforma onde residem os contratos

        contract_addresses (obrigatorio) - endereços dos contratos, separados por virgula se forem mais que 1

        vs_currencies (obrigatorio) - moedas de referencia, separadas por virgula se forem mais que 1"""
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id_platform": "",
        "contract_addresses": "",
        "vs_currencies": "",
        "include_market_cap": "",
        "include_24hr_vol": "",
        "include_24hr_change": "",
        "include_last_updated_at": "",
        "precision": "",
    }
    # validacao de parametros
    # id_platform ('id' já existe como metodo, não pode ser usado)
    if not isinstance(id_platform, str):
        raise TypeError("'id_platform' tem de ser do tipo 'str'")
    if id_platform == "":
        raise ValueError("'id_platform' tem de ser definido")
    api_parameters["id"] = id_platform
    # contract_addresses
    if not isinstance(contract_addresses, str):
        raise TypeError("'contract_addresses' tem de ser do tipo 'str'")
    if contract_addresses == "":
        raise ValueError("'contract_addresses' tem de ser definido")
    api_parameters["contract_addresses"] = contract_addresses
    # vs_currencies
    if not isinstance(vs_currencies, str):
        raise TypeError("'vs_currencies' tem de ser do tipo 'str'")
    if vs_currencies == "":
        raise ValueError("'vs_currencies' tem de ser definido")
    api_parameters["vs_currencies"] = vs_currencies
    # include_market_cap
    if not isinstance(include_market_cap, bool):
        include_market_cap = False
    if include_market_cap != False:
        api_parameters["include_market_cap"] = str(include_market_cap).lower()
    # include_24hr_vol
    if not isinstance(include_24hr_vol, bool):
        include_24hr_vol = False
    if include_24hr_vol != False:
        api_parameters["include_24hr_vol"] = str(include_24hr_vol).lower()
    # include_24hr_change
    if not isinstance(include_24hr_change, bool):
        include_24hr_change = False
    if include_24hr_change != False:
        api_parameters["include_24hr_change"] = str(
            include_24hr_change).lower()
    # include_last_updated_at
    if not isinstance(include_last_updated_at, bool):
        include_last_updated_at = False
    if include_last_updated_at != False:
        api_parameters["include_last_updated_at"] = str(
            include_last_updated_at).lower()
    # precision
    if not isinstance(precision, (int, str)):
        raise TypeError("'precision' tem de ser do tipo 'int' ou 'str'")
    if isinstance(precision, str):
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        precision = str(precision)
    api_parameters["precision"] = precision

    return API(f"simple/token_price/{api_parameters['id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# id_plataforma = 'ethereum'
# enderecos_contracto = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599,0x4594cffbfc09bc5e7ecf1c2e1c1e24f0f7d29036'
# url, codigo, dados = coin_price_by_token_addresses(id_plataforma, enderecos_contracto, 'eur')
# print(f'url: {url}')
# if codigo == 200:
#     for contrato in dados:
#         print(f'{contrato}')
#         for vs_currency in dados[contrato]:
#             print(f'\t{vs_currency}: {dados[contrato][vs_currency]}')
# else:
#     print(f'erro {codigo}: {dados}')


def supported_currencies_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/simple-supported-currencies

    este endpoint permite consultar quais as moedas de referencia suportadas pela CoinGecko"""
    return API("simple/supported_vs_currencies", {})


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = supported_currencies_list()
# print(f'url: {url}')
# if codigo == 200:
#     for moeda in dados:
#         print(f'{moeda}')
# else:
#     print(f'erro {codigo}: {dados}')


def coins_list(include_platform: bool = False) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-list

    obter todas as moedas suportadas em CoinGecko com IDs, nome,
    simbolo e (no caso de contractos) endereco na plataforma das moedas
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "include_platform": "",
    }
    # validacao parametros
    # include_platform
    if not isinstance(include_platform, bool):
        include_platform = False
    if include_platform:
        api_parameters["include_platform"] = str(True).lower()

    return API("coins/list", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coins_list(include_platform=False)
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(item)
# else:
#     print(f'erro {codigo}: {dados}')


# lista auxiliar para ordenação dos dados retornados por coins_list_with_market_data()
# lista_tipos_ordenacao = [
#     'market_cap_asc',
#     'market_cap_desc',
#     'volume_asc',
#     'volume_desc',
#     'id_asc',
#     'id_desc'
# ]
# lista auxiliar para parametro 'price_change_percentage'
# lista_timeframe_price_change = [
#     '1h',
#     '24h',
#     '7d',
#     '14d',
#     '30d',
#     '200d',
#     '1y'
# ]
def coins_list_with_market_data(
    vs_currency: str = "",
    ids: str = "",
    category: str = "",
    order: str = "",
    per_page: int = 100,
    page: int = 0,
    sparkline: bool = False,
    price_change_percentage: str = "",
    locale: str = "",
    precision: int | str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """
    https://docs.coingecko.com/v3.0.1/reference/coins-markets

    consultar preço, cap mercado, volume e dados de mercado de todas as moedas suportadas

    """
    # dicionario de parametros para passar para a API, todos os valores tem de ser do tipo 'str'
    api_parameters: dict[str, str] = {
        "vs_currency": "",
        "ids": "",
        "category": "",
        "order": "",
        "per_page": "",
        "page": "",
        "sparkline": "",
        "price_change_percentage": "",
        "locale": "",
        "precision": "",
    }
    # validação de parametros
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "" or vs_currency == " ":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # ids
    if not isinstance(ids, str):
        raise TypeError("'ids' tem de ser do tipo 'str'")
    if ids != "":
        api_parameters["ids"] = ids
    # category
    if not isinstance(category, str):
        raise TypeError("'category' tem de ser do tipo 'str'")
    if category != "":
        api_parameters["category"] = category
    if ids == "" and category == "":
        raise ValueError("'ids' ou 'category' têm de ser definidos")
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")
    # if not order in lista_tipos_ordenacao:
    #     order = lista_tipos_ordenacao[1]
    api_parameters["order"] = order
    # per_page
    if not isinstance(per_page, int):
        raise TypeError("'per_page' tem de ser do tipo 'int'")
    if (per_page < 1) or (per_page > 250):
        per_page = 100
    api_parameters["per_page"] = str(per_page)
    # page
    if not isinstance(page, int):
        raise TypeError("'page' tem de ser do tipo 'int'")
    api_parameters["page"] = str(page)
    # sparkline
    if not isinstance(sparkline, bool):
        raise TypeError("'sparkline' tem de ser do tipo 'bool'")
    if sparkline:
        api_parameters["sparkline"] = str(True).lower()
    # price_change_percentage
    if not isinstance(price_change_percentage, str):
        raise TypeError("'price_change_percentage' tem de ser do tipo 'str'")
    # for timeframe in price_change_percentage.split(','):
    #     if not timeframe in lista_timeframe_price_change:
    #         price_change_percentage = lista_timeframe_price_change[0]
    #     else:
    #         price_change_percentage += f',{timeframe}'
    api_parameters["price_change_percentage"] = price_change_percentage
    # locale
    if not isinstance(locale, str):
        raise TypeError("'locale' tem de ser do tipo 'str'")
    api_parameters["locale"] = locale
    # precision
    if precision != "":
        if not isinstance(precision, (int, str)):
            raise TypeError("'precision' tem de ser do tipo 'int' ou 'str'")
        if isinstance(precision, str):
            if precision == "full":
                precision = "18"
            precision = int(precision)
        if isinstance(precision, int):
            if precision < 0:
                precision = 0
            if precision > 18:
                precision = 18
            precision = str(precision)
        api_parameters["precision"] = precision

    return API("coins/markets", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coins_list_with_market_data('eur', 'bitcoin')
# print(f'url: {url}')
# if codigo == 200:
#     print(f'codigo: {codigo}')
#     for item in dados:
#         print(item)
# else:
#     print(f'erro {codigo}: {dados}')


def coin_data_by_id(
    id_criptomoeda: str = "",
    localization: bool = True,
    tickers: bool = True,
    market_data: bool = True,
    community_data: bool = True,
    developer_data: bool = True,
    sparkline: bool = False,
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id

    este endpoint permite fazer uma consulta a todos os dados de uma moeda
    (nome, preço, dados mercado... incluindo tickers de correctora) na
    CoinGecko com base numa id de moeda
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "localization": "",
        "tickers": "",
        "market_data": "",
        "community_data": "",
        "developer_data": "",
        "sparkline": "",
    }
    # validação de parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == "":
        raise ValueError("'id_criptomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # localization
    if not isinstance(localization, bool):
        raise TypeError("'localization' tem de ser do tipo 'bool'")
    if not localization:
        api_parameters["localization"] = str(localization).lower()
    # tickers
    if not isinstance(tickers, bool):
        raise TypeError("'tickers' tem de ser do tipo 'bool'")
    if not tickers:
        api_parameters["tickers"] = str(tickers).lower()
    # market_data
    if not isinstance(market_data, bool):
        raise TypeError("'market_data' tem de ser do tipo 'bool'")
    if not market_data:
        api_parameters["market_data"] = str(market_data).lower()
    # community_data
    if not isinstance(community_data, bool):
        raise TypeError("'community_data' tem de ser do tipo 'bool'")
    if not community_data:
        api_parameters["community_data"] = str(community_data).lower()
    # developer_data
    if not isinstance(developer_data, bool):
        raise TypeError("'developer_data' tem de ser do tipo 'bool'")
    if not developer_data:
        api_parameters["developer_data"] = str(developer_data).lower()
    # sparkline
    if not isinstance(sparkline, bool):
        raise TypeError("'sparkline' tem de ser do tipo 'bool'")
    if sparkline:
        api_parameters["sparkline"] = str(sparkline).lower()

    return API(f"coins/{api_parameters['id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_data_by_id('bitcoin')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_tickers_by_id(
    id_criptomoeda: str = "",
    exchange_ids: str = "",
    include_exchange_logo: bool = False,
    page: int = -1,
    order: str = "",
    depth: bool = False,
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id-tickers

    este endpoint permite fazer uma consulta de tickers tanto em
    correctoras centralizadas como descentralizadas a partir de um id
    de moeda
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "exchange_ids": "",
        "include_exchange_logo": "",
        "page": "",
        "order": "",
        "depth": "",
    }
    # validacao parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == "":
        raise ValueError("'id_cripomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # exchange_ids
    if not isinstance(exchange_ids, str):
        raise TypeError("'exchange_ids' tem de ser do tipo 'str'")
    if exchange_ids != "":
        api_parameters["exchange_ids"] = exchange_ids
    # include_exchange_logo
    if not isinstance(include_exchange_logo, bool):
        raise TypeError("'include_exchange_logo' tem de ser do tipo 'str'")
    if include_exchange_logo:
        api_parameters["include_exchange_logo"] = str(
            include_exchange_logo).lower()
    # page
    if not isinstance(page, int | None):
        raise TypeError("'page' tem de ser do tipo 'int'")
    if page != None:
        if page < 1:
            page = 1
        api_parameters["page"] = str(page)
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")
    if order != "":
        api_parameters["order"] = order
    # depth
    if not isinstance(depth, bool):
        raise TypeError("'depth' tem de ser do tipo 'bool'")
    if depth:
        api_parameters["depth"] = str(depth).lower()

    return API(f"coins/{api_parameters['id']}/tickers", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_tickers_by_id('bitcoin',include_exchange_logo=True)
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_historical_data_by_id(
    id_criptomoeda: str = "", date: str = "", localization: bool = True
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id-history

    este endpoint permite fazer consulta de dados historicos (preco, cap mercado, volume 24h,
    etc) sobre uma moeda numa determinada data, passando o id da moeda.
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "date": "",
        "localization": "",
    }
    # validacao de parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == None or id_criptomoeda == "":
        raise ValueError("'id_criptomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # date
    if not isinstance(date, str):
        raise TypeError("'date' tem de ser do tipo 'str'")
    if date == "" or date == None:
        raise ValueError("'date' tem de ser definido")
    if date != "":
        api_parameters["date"] = date
    # localization
    if not isinstance(localization, bool):
        raise TypeError("'localization' tem de ser do tipo 'bool'")
    if not localization:
        api_parameters["localization"] = str(localization).lower()

    return API(f"coins/{api_parameters['id']}/history", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_historical_data_by_id('bitcoin','10-12-2023',localization=False)
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(item)
# else:
#     print(f'erro {codigo}: {dados}')


def coin_historical_chart_data_by_id(
    id_criptomoeda: str = "",
    vs_currency: str = "",
    days: str = "",
    interval: str = "",
    precision: int | str = "full",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id-market-chart

    este endpoint permite fazer consulta para obter dados historicos graficos que
    incluem tempo unix, preco, capitalizacao mercado e volume 24h a partir de um id de moeda
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "vs_currency": "",
        "days": "",
        "interval": "",
        "precision": "",
    }
    # validacao de parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == "":
        raise ValueError("'id_criptomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # days
    if not isinstance(days, str):
        raise TypeError("'days' tem de ser do tipo 'str'")
    if days == "":
        raise ValueError("'days' tem de ser definido")
    api_parameters["days"] = days
    # interval
    if not isinstance(interval, str):
        raise TypeError("'interval' tem de ser do tipo 'str'")
    if interval != "":
        api_parameters["interval"] = interval
    # precision
    if not isinstance(precision, (int, str)):
        raise TypeError("'precision' tem de ser do tipo 'str' ou 'int'")
    if isinstance(precision, str):
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        api_parameters["precision"] = str(precision)

    return API(f"coins/{api_parameters['id']}/market_chart", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_historical_chart_data_by_id('bitcoin', 'eur', '30')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


# temos de criar outra abordagem, este noma de chamada api é enorme...
def coin_historical_chart_data_within_time_range_by_id(
    id_criptomoeda: str = "",
    vs_currency: str = "",
    from_unix: int = -1,
    to_unix: int = -1,
    precision: str | int = "full",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id-market-chart-range

    este endpoint permite obter dados historicos graficos compreendidos num periodo de tempo
    unix com preco, capitalizacao de mercado e volume 24hrs a partir de um id de moeda
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "vs_currency": "",
        "from": "",
        "to": "",
        "precision": "",
    }
    # validacao parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == "":
        raise ValueError("'id_criptomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # from_unix (como 'from' é nome reservado, foi usado outro nome)
    if not isinstance(from_unix, int):
        raise TypeError("'from_unix' tem de ser do tipo 'int'")
    if from_unix == -1:
        raise ValueError("'from_unix' tm de ser definido")
    api_parameters["from"] = str(from_unix)
    # to_unix ('to' não é nome reservado, mas foi usado este nome para manter relação)
    if not isinstance(to_unix, int):
        raise TypeError("'to_unix' tem de ser do tipo 'int'")
    if to_unix == -1:
        raise ValueError("'to_unix' tem de ser definido")
    api_parameters["to"] = str(to_unix)
    # precision
    if not isinstance(precision, (int, str)):
        raise TypeError("'precision' tem de ser do tipo '(int, str)'")
    if isinstance(precision, str):
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        api_parameters["precision"] = str(precision)

    return API(f"coins/{api_parameters['id']}/market_chart/range", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_historical_chart_data_within_time_range_by_id('bitcoin','eur',1711929600,1712275200)
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_ohlc_chart_by_id(
    id_criptomoeda: str = "",
    vs_currency: str = "",
    days: str = "",
    precision: str | int = "full",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-id-ohlc

    este endpoint permite fazer consulta ao gráfico OHLC (Open, High, Low, Close)
    de uma moeda usando o seu id
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "vs_currency": "",
        "days": "",
        "precision": "",
    }
    # validacao de parametros
    # id_criptomoeda (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_criptomoeda, str):
        raise TypeError("'id_criptomoeda' tem de ser do tipo 'str'")
    if id_criptomoeda == "":
        raise ValueError("'id_criptomoeda' tem de ser definido")
    api_parameters["id"] = id_criptomoeda
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # days
    if not isinstance(days, str):
        raise TypeError("'days' tem de ser do tipo 'str'")
    if days == "":
        raise ValueError("'days' tem de ser definido")
    api_parameters["days"] = days
    # precision
    if not isinstance(precision, (str, int)):
        raise TypeError("'precision' tem de ser do tipo '(str, int)'")
    if isinstance(precision, str):
        if precision != "full":
            precision = "full"
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        precision = str(precision)
    api_parameters["precision"] = precision

    return API(f"coins/{api_parameters['id']}/ohlc", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_ohlc_chart_by_id('bitcoin','eur','1')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_data_by_token_address(
    id_platform: str = "", contract_address: str = ""
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-contract-address

    este endpoint permite consultar todos os dados de uma moeda (nome, preço, mercado...
    incluindo tickers das correctoras) nda pagina da CoinGecko a partir da plataforma do activo
    e do endereço do contrato do token
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "contract_address": "",
    }
    # validação de parametros
    # id_platform (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_platform, str):
        raise TypeError("'id_platform' tem de ser do tipo 'str'")
    if id_platform == "":
        raise ValueError("'id_platform' tem de ser definido")
    api_parameters["id"] = id_platform
    # contract_address
    if not isinstance(contract_address, str):
        raise TypeError("'contract_address' tem de ser do tipo 'str'")
    if contract_address == "":
        raise ValueError("'contract_address' tem de ser definido")
    api_parameters["contract_address"] = contract_address

    return API(
        f"coins/{api_parameters['id']
                 }/contract/{api_parameters['contract_address']}",
        {},
    )


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_data_by_token_address('ethereum','0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_historical_chart_data_by_token_address(
    id_platform: str = "",
    contract_address: str = "",
    vs_currency: str = "",
    days: str = "",
    interval: str = "",
    precision: str | int = "full",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/contract-address-market-chart

    este endpoint permite consultar dados historicos graficos incluindo tempo UNIX,
    preco, capitalização de mercado e volume 24hrs a partir da plataforma do activo e
    endereco de contracto do token
    """
    # dicionario parameters
    api_parameters: dict[str, str] = {
        "id": "",
        "contract_address": "",
        "vs_currency": "",
        "days": "",
        "interval": "",
        "precision": "",
    }
    # validacao de parametros
    # id_platform (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_platform, str):
        raise TypeError("'id_platform' tem de ser do tipo 'str'")
    if id_platform == "":
        raise ValueError("'id_platform' tem de ser definido")
    api_parameters["id"] = id_platform
    # contract_address
    if not isinstance(contract_address, str):
        raise TypeError("'contract_address' tem de ser do tipo 'str'")
    if contract_address == "":
        raise ValueError("'contract_address' tem de ser definido")
    api_parameters["contract_address"] = contract_address
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # days
    if not isinstance(days, str):
        raise TypeError("'days' tem de ser do tipo 'str'")
    if days == "":
        raise ValueError("'days' tem de ser definido")
    api_parameters["days"] = days
    # interval
    if not isinstance(interval, str):
        raise TypeError("'interval' tem de ser do tipo 'str'")
    api_parameters["interval"] = interval
    # precision
    if not isinstance(precision, (str, int)):
        raise TypeError("'precision' tem de ser do tipo '(str, int)'")
    if isinstance(precision, str):
        if precision != "full":
            precision = "full"
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        precision = str(precision)
    api_parameters["precision"] = precision

    return API(
        f"coins/{api_parameters['id']}/contract/{
            api_parameters['contract_address']
        }/market_chart",
        api_parameters,
    )


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_historical_chart_data_by_token_address('ethereum','0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48','eur','1')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def coin_historical_chart_data_within_time_range_by_token_address(
    id_plataforma: str = "",
    contract_address: str = "",
    vs_currency: str = "",
    from_unix: int = -1,
    to_unix: int = -1,
    precision: str | int = "full",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/contract-address-market-chart-range

    est endpoint permite obter dados historicos graficos compreendidos num determinado
    periodo de tempo UNIX, tais como preco, capitalizacao de mercado e volume 24hrs a
    partir da plataforma do activo e o seu endereco de contrato
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "contract_address": "",
        "vs_currency": "",
        "from": "",
        "to": "",
        "precision": "",
    }
    # validacao de parametros
    # id_platform (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_plataforma, str):
        raise TypeError("'id_plataforma' tem de ser do tipo 'str'")
    if id_plataforma == "":
        raise ValueError("'id_plataforma' tem de ser definido")
    api_parameters["id"] = id_plataforma
    # contract_address
    if not isinstance(contract_address, str):
        raise TypeError("'contract_address' tem de ser do tipo 'str'")
    if contract_address == "":
        raise ValueError("'contract_address' tem de ser definido")
    api_parameters["contract_address"] = contract_address
    # vs_currency
    if not isinstance(vs_currency, str):
        raise TypeError("'vs_currency' tem de ser do tipo 'str'")
    if vs_currency == "":
        raise ValueError("'vs_currency' tem de ser definido")
    api_parameters["vs_currency"] = vs_currency
    # from_unix (como 'from' é nome reservado, foi usado outro nome)
    if not isinstance(from_unix, int):
        raise TypeError("'from_unix' tem de ser do tipo 'int'")
    if from_unix == -1:
        raise ValueError("'from_unix' tem de ser definido")
    api_parameters["from"] = str(from_unix)
    # to_unix ('to' não é nome reservado, mas foi usado para manter logica)
    if not isinstance(to_unix, int):
        raise TypeError("'to_unix' tem de ser do tipo 'int'")
    if to_unix == -1:
        raise ValueError("'to_unix' tem de ser definido")
    api_parameters["to"] = str(to_unix)
    # precision
    if not isinstance(precision, (str, int)):
        raise TypeError("'precision' tem de ser do tipo '(str, int)'")
    if isinstance(precision, str):
        if precision != "full":
            precision = "full"
        if precision == "full":
            precision = "18"
        precision = int(precision)
    if isinstance(precision, int):
        if precision < 0:
            precision = 0
        if precision > 18:
            precision = 18
        precision = str(precision)
    api_parameters["precision"] = precision

    return API(
        f"coins/{api_parameters['id']}/contract/{
            api_parameters['contract_address']
        }/market_chart/range",
        api_parameters,
    )


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coin_historical_chart_data_within_time_range_by_token_address('ethereum','0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48','eur',1711929600,1712275200)
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def assets_platforms_list(filter: str = "") -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/asset-platforms-list

    este endpoint permite fazer obter a lista de todas as plataformas
    de activos na CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "filter": "",
    }
    # validacao de parametros
    if not isinstance(filter, str):
        raise TypeError("'filter' tem de ser do tipo 'str'")
    api_parameters["filter"] = filter

    return API(f"asset_platforms", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = assets_platforms_list('nft')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def coins_categories_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-categories-list

    este endpoint permite obter todas as categorias de moedas da CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validação de parametros
    return API(f"coins/categories/list", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coins_categories_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def coins_categories_list_with_market_data(
    order: str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/coins-categories

    este endpoint permite obter a lista de categorias de moedas da CoinGecko,
    com dados de mercado (capitalização de mercado, volume, etc)
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {"order": ""}
    # validacao de parametros
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")

    return API(f"coins/categories", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = coins_categories_list_with_market_data()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def exchanges_list_with_data(
    per_page: int = -1,
    page: int = -1,
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchanges

    este endpoit permite obter todos os dados (id, nome, pais, etc)
    das correctoras suportadas que têm volumes de transacoes activas na CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "per_page": "",
        "page": "",
    }
    # validacao de parametros
    # per_page
    if not isinstance(per_page, int):
        raise TypeError("'per_page' tem de ser do tipo 'int'")
    if per_page != -1:
        api_parameters["per_page"] = str(per_page)
    # page
    if not isinstance(page, int):
        raise TypeError("'page' tem de ser do tipo 'int'")
    if page != -1:
        api_parameters["page"] = str(page)

    return API(f"exchanges", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = exchanges_list_with_data()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def exchanges_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchanges-list

    este endpoint permite obter uma lista com o id e nome de todas
    as correctoras
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"exchanges/list", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = exchanges_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def exchange_data_by_id(id_exchange: str = "") -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchanges-id

    este endpoint permite obter dados sobre uma correctora (nome, data de estabelecimento,
    pais, etc), volume em BTC da correctora e top 100 tickers a partir do id da correctora
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
    }
    # validacao de parametros
    # id_exchange (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_exchange, str):
        raise TypeError("'id_exchange' tem de ser do tipo 'str'")
    if id_exchange == "":
        raise ValueError("'id_exchange' tem de ser definido")
    api_parameters["id"] = id_exchange

    return API(f"exchanges/{api_parameters['id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = exchange_data_by_id('binance')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def exchange_tickers_by_id(
    id_exchange: str = "",
    coin_ids: str = "",
    include_exchange_logo: bool = False,
    page: int = -1,
    depth: bool = False,
    order: str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchanges-id-tickers

    este endpoint permite obter os tickers de uma correctora a partir
    da id da correctora
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "coin_ids": "",
        "include_exchange_logo": "",
        "page": "",
        "depth": "",
        "order": "",
    }
    # validacao de parametros
    # id_exchange (como 'id' é nome reservado, foi usado outro nome )
    if not isinstance(id_exchange, str):
        raise TypeError("'id_exchange' tem de ser do tipo 'str'")
    if id_exchange == "":
        raise ValueError("'id_exchange' tem de ser definido")
    api_parameters["id"] = id_exchange
    # coin_ids
    if not isinstance(coin_ids, str):
        raise TypeError("'coin_ids' tem de ser do tipo 'str'")
    if coin_ids == "":
        raise ValueError("'coin_ids' tem de ser definido")
    api_parameters["coin_ids"] = coin_ids
    # include_exchange_logo
    if not isinstance(include_exchange_logo, bool):
        raise TypeError("'include_exchange_logo' tem de ser do tipo 'bool'")
    if include_exchange_logo != False:
        api_parameters["include_exchange_logo"] = str(True)
    # page
    if not isinstance(page, int):
        raise TypeError("'page' tem de ser do tipo 'int'")
    api_parameters["page"] = str(page)
    # depth
    if not isinstance(depth, bool):
        raise TypeError("'depth' tem de ser do tipo 'bool'")
    if depth != False:
        api_parameters["depth"] = str(True)
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")
    api_parameters["order"] = order

    return API(f"exchanges/{api_parameters['id']}/tickers", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = exchange_tickers_by_id('binance', 'bitcoin,dogecoin')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def exchange_volume_chart_by_id(
    id_exchange: str = "", days: str = ""
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchanges-id-volume-chart

    este endpoint permite obter dados de volume historico grafico com tempo UNIX e
    volume de negociação em BTC a partir do id da correctora
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "days": "",
    }
    # validacao de parametros
    # id_exchanges (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_exchange, str):
        raise TypeError("'id_exchange' tem de ser do tipo 'str'")
    if id_exchange == "":
        raise ValueError("'id_exchange' tem de ser definido")
    api_parameters["id"] = id_exchange
    # days
    if not isinstance(days, str):
        raise TypeError("'days' tem de ser do tipo 'str'")
    if days == "":
        raise ValueError("'days' tem de ser definido")
    api_parameters["days"] = days

    return API(f"exchanges/{api_parameters['id']}/volume_chart", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = exchange_volume_chart_by_id('binance','30')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def derivatives_tickers_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/derivatives-tickers

    este endpoint permite obter uma lista com dados dos tickers das correctoras
    de derivativos da CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"derivatives", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = derivatives_tickers_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def derivatives_exchange_list_with_data(
    order: str = "", per_page: int = -1, page: int = -1
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/derivatives-exchanges

    este endpoint permite obter todas as correctoras de derivativos com os seus dados (id,
    nome, contractos em aberto, etc) disponiveis na CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "order": "",
        "per_page": "",
        "page": "",
    }
    # validacao de parametros
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")
    api_parameters["order"] = order
    # per_page
    if not isinstance(per_page, int):
        raise TypeError("'per_page' tem de ser do tipo 'int'")
    if per_page != -1:
        api_parameters["per_page"] = str(per_page)
    # page
    if not isinstance(page, int):
        raise TypeError("'page' tem de ser do tipo 'int'")
    if page != -1:
        api_parameters["page"] = str(page)

    return API(f"derivatives/exchanges", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = derivatives_exchange_list_with_data('open_interest_bts_desc')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def derivatives_exchange_data_by_id(
    id_exchange: str = "",
    include_tickers: str = "",
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/derivatives-exchanges-id

    este endpoint permite obter os dados relativos a uma correctora de derivados (id, nome,
    contractos em aberto, etc) a partir do id da correctora)
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
        "include_tickers": "",
    }
    # validacao de parametros
    # id_exchange (como 'id' é nome reservado, foi usado outro nome)
    if not isinstance(id_exchange, str):
        raise TypeError("'id_exchange' tem de ser do tipo 'str'")
    if id_exchange == "":
        raise ValueError("'id_exchange' tem de ser definido")
    api_parameters["id"] = id_exchange
    # include_tickers
    if not isinstance(include_tickers, str):
        raise TypeError("'include_tickers' tem de ser do tipo 'str'")
    api_parameters["include_tickers"] = include_tickers

    return API(f"derivatives/exchanges/{api_parameters['id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = derivatives_exchange_data_by_id('binance_futures')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def derivatives_exchanges_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/derivatives-exchanges-list

    este endpoint permite obter uma lista dos derivados de correctoras com id
    e nome da CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"derivatives/exchanges/list", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = derivatives_exchanges_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def nfts_list(
    order: str = "", per_page: int = -1, page: int = -1
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/nfts-list

    este endpoint permite obter todos os NFTs suportados com id, endereço de contracto,
    nome, id da platforma do activo e o simbolo da CoinGecko
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "order": "",
        "per_page": "",
        "page": "",
    }
    # validacao de parametros
    # order
    if not isinstance(order, str):
        raise TypeError("'order' tem de ser do tipo 'str'")
    api_parameters["order"] = order
    # per_page
    if not isinstance(per_page, int):
        raise TypeError("'per_page' tem de ser do tipo 'int'")
    if per_page != -1:
        api_parameters["per_page"] = str(per_page)
    # page
    if not isinstance(page, int):
        raise TypeError("'page' tem de ser do tipo 'int'")
    if page != -1:
        api_parameters["page"] = str(page)

    return API(f"nfts/list", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = nfts_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}')
# else:
#     print(f'erro {codigo}: {dados}')


def nfts_collection_data_by_id(id_nft: str = "") -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/nfts-id

    este endpoint permite obter todos os dados do NTF (nome, preco minimo,
    volume 24hrs, etc) a partir do id da coleccao NFT
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "id": "",
    }
    # validacao de parametros
    # id_nft ( como 'id' é um nome reservado, foi usado outro nome)
    if not isinstance(id_nft, str):
        raise TypeError("'id_nft' tem de ser do tipo 'str'")
    if id_nft == "":
        raise ValueError("'id_nft' tem de ser definido")
    api_parameters["id"] = id_nft

    return API(f"nfts/{api_parameters['id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = nfts_collection_data_by_id('pudgy-penguins')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def nfts_collection_data_by_contract_address(
    asset_platform_id: str = "", contract_address: str = ""
) -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/nfts-contract-address

    este endpoint permite obter toda a informação do NFT (nome, preco minimo, volume 24hrs, etc)
    a partir do endereco de contracto da colecao NFT e respectiva plataforma de activo
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "asset_platform_id": "",
        "contract_address": "",
    }
    # validacao de parametros
    # asset_platform_id
    if not isinstance(asset_platform_id, str):
        raise TypeError("'asset_platform_id' tem de ser do tipo 'str'")
    if asset_platform_id == "":
        raise ValueError("'asset_platform_id' tem de ser definido")
    api_parameters["asset_platform_id"] = asset_platform_id
    # contract_address
    if not isinstance(contract_address, str):
        raise TypeError("'contract_address' tem de ser do tipo 'str'")
    if contract_address == "":
        raise ValueError("'contract_address' tem de ser definido")
    api_parameters["contract_address"] = contract_address

    return API(
        f"nfts/{api_parameters['asset_platform_id']}/contract/{
            api_parameters['contract_address']
        }",
        api_parameters,
    )


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = nfts_collection_data_by_contract_address('ethereum', '0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def btc_to_currency_exchange_rates() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/exchange-rates

    este endpoint permite consultar a taxa de conversão BTC com outras moedas
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"exchange_rates", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = btc_to_currency_exchange_rates()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def search_queries(query: str = "") -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/search-data

    este endpoint permite realizar um pesquisa por moedas, categorias e mercados listados em CoinGecko
    """
    # dicionario parametros
    api_parameters: dict[str, str] = {
        "query": "",
    }
    # validacao de parametros
    if not isinstance(query, str):
        raise TypeError("'query' tem de ser do tipo 'str'")
    if query == "":
        raise ValueError("'query' tem de ser definido")
    api_parameters["query"] = query

    return API(f"search", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = search_queries('dogecoin')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def trending_search_list() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/trending-search

    este endpoint permite consultar as moedas, nfts e categorias com mais procura na
    CoinGecko nas ultimas 24hrs
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"search/trending", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = trending_search_list()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def crypto_global_market_data() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/crypto-global

    este endpoint permite consultar dados globais de criptomoedas incluindo
    criptomoedas activas, mercados, total de capitalizacao de mercado de
    criptomoedas, etc
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros

    return API(f"global", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = crypto_global_market_data()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def global_defi_market_data() -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/global-defi

    este endpoint permite consultar os dados do top100 global das financas descentralizadas
    de criptomoedas, incluindo capitalizacao de mercado DeFi e volume de negociacao
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {}
    # validacao de parametros
    return API(f"global/decentralized_finance_defi", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = global_defi_market_data()
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')


def public_companies_holdings(coin_id: str = "") -> tuple[str, int, dict[Any, Any]]:
    """https://docs.coingecko.com/v3.0.1/reference/companies-public-treasury

    este endpoint permite consultar a participação/posse de BTC ou ETH de empresas
    """
    # dicionario de parametros
    api_parameters: dict[str, str] = {
        "coin_id": "",
    }
    # validacao de parametros
    if not isinstance(coin_id, str):
        raise TypeError("'coin_id' tem de ser do tipo 'str'")
    if coin_id == "":
        raise ValueError("'coin_id' tem de ser definido")
    api_parameters["coin_id"] = coin_id

    return API(f"companies/public_treasury/{api_parameters['coin_id']}", api_parameters)


# debug (decomentar linhas seguintes para testar funcao)
# url, codigo, dados = public_companies_holdings('bitcoin')
# print(f'url: {url}')
# if codigo == 200:
#     for item in dados:
#         print(f'{item}: {dados[item]}')
# else:
#     print(f'erro {codigo}: {dados}')
