"""
In order to have metrics, which require different order, we need to have transform
 functions, which reorder or make different dictionaries in general.
"""

import operator
from san.pandas_utils import convert_to_datetime_idx_df
from functools import reduce
from collections import OrderedDict
from san.error import SanError
from san.sanbase_graphql_helper import QUERY_MAPPING

QUERY_PATH_MAP = {
    "eth_top_transactions": ["ethTopTransactions"],
    "eth_spent_over_time": ["ethSpentOverTime"],
    "token_top_transactions": ["tokenTopTransactions"],
    "get_metric": ["timeseriesDataJson"],
    "get_metric_many": ["timeseriesDataPerSlugJson"],
    "topic_search": ["chartData"],
}


def path_to_data(idx, query, data):
    """
    With this function we jump straight onto the key from the dataframe,
    that we want and start from there. We use our future starting points from the QUERY_PATH_MAP.
    """
    return reduce(
        operator.getitem,
        [
            "query_" + str(idx),
        ]
        + QUERY_PATH_MAP[query],
        data,
    )


def transform_timeseries_data_query_result(idx, query, data):
    """
    If there is a transforming function for this query, then the result is
    passed for it for another transformation
    """
    if query in QUERY_PATH_MAP:
        result = path_to_data(idx, query, data)
    elif query in QUERY_MAPPING:
        result = data["query_" + str(idx)]
    else:
        result = path_to_data(idx, "get_metric", data)

    if query + "_transform" in globals():
        result = globals()[query + "_transform"](result)

    return convert_to_datetime_idx_df(result)


def transform_timeseries_data_per_slug_query_result(idx, query, data):
    if query in QUERY_MAPPING:
        raise SanError(f"The get_many call is available only for get_metric. Called with {query}")

    result = path_to_data(idx, "get_metric_many", data)
    rows = []

    for datetime_point in result:
        row = {"datetime": datetime_point["datetime"]}
        for slug_data in datetime_point["data"]:
            row[slug_data["slug"]] = slug_data["value"]

        rows.append(row)

    return convert_to_datetime_idx_df(rows)


def eth_top_transactions_transform(data):
    return list(
        map(
            lambda column: {
                "datetime": column["datetime"],
                "fromAddress": column["fromAddress"]["address"],
                "fromAddressIsExchange": column["fromAddress"]["isExchange"],
                "toAddress": column["toAddress"]["address"],
                "toAddressIsExchange": column["toAddress"]["isExchange"],
                "trxHash": column["trxHash"],
                "trxValue": column["trxValue"],
            },
            data,
        )
    )


def top_transfers_transform(data):
    return list(
        map(
            lambda column: {
                "datetime": column["datetime"],
                "fromAddress": column["fromAddress"]["address"],
                "toAddress": column["toAddress"]["address"],
                "trxHash": column["trxHash"],
                "trxValue": column["trxValue"],
            },
            data,
        )
    )


def news_transform(data):
    result = list(
        map(
            lambda column: OrderedDict(
                {
                    "datetime": column["datetime"],
                    "title": column["title"],
                    "description": column["description"],
                    "sourceName": column["sourceName"],
                    "url": column["url"],
                }
            ),
            data,
        )
    )

    return result


def token_top_transactions_transform(data):
    return list(
        map(
            lambda column: {
                "datetime": column["datetime"],
                "fromAddress": column["fromAddress"]["address"],
                "fromAddressIsExchange": column["fromAddress"]["isExchange"],
                "toAddress": column["toAddress"]["address"],
                "toAddressIsExchange": column["toAddress"]["isExchange"],
                "trxHash": column["trxHash"],
                "trxValue": column["trxValue"],
            },
            data,
        )
    )


def emerging_trends_transform(data):
    result = []
    for column in data:
        for i in range(0, len(column["topWords"])):
            result.append(
                {"datetime": column["datetime"], "score": column["topWords"][i]["score"], "word": column["topWords"][i]["word"]}
            )
    result.sort(key=lambda elem: elem["datetime"])

    return result


def top_social_gainers_losers_transform(data):
    result = []
    for column in data:
        for i in range(0, len(column["projects"])):
            result.append(
                {
                    "datetime": column["datetime"],
                    "slug": column["projects"][i]["slug"],
                    "change": column["projects"][i]["change"],
                    "status": column["projects"][i]["status"],
                }
            )

    result = list(
        map(
            lambda column: OrderedDict(
                {"datetime": column["datetime"], "slug": column["slug"], "change": column["change"], "status": column["status"]}
            ),
            result,
        )
    )

    return result
