import time

from bitquote_client.client.client import BitquoteClient

from conio_sdk.generated_protobuf import v1_pb2
from conio_sdk.logging.factory import LOGGING_FACTORY


class PriceVOService:
    _PB_TO_STR_CURRENCIES = {
        v1_pb2.EUR: 'EUR',
        v1_pb2.USD: 'USD',
    }

    def __init__(self, quoting_client: BitquoteClient):
        self._quoting_client = quoting_client

    def get_current_price(self, msg: v1_pb2.MsgGetCurrentPrice) -> v1_pb2.PricePoint:
        buy_price = self._quoting_client.get_fiat_buy_price(
            msg.satoshi_amount or 10**8,
            self._PB_TO_STR_CURRENCIES[msg.currency],
        )
        sell_price = self._quoting_client.get_fiat_sell_price(
            msg.satoshi_amount or 10 ** 8,
            self._PB_TO_STR_CURRENCIES[msg.currency],
        )
        return v1_pb2.PricePoint(
            buy_price=float(buy_price),
            sell_price=float(sell_price),
            timestamp=int(time.time() * 1000)
        )

    def get_historical_prices(self, msg: v1_pb2.MsgHistoryPrices) -> v1_pb2.MsgHistoryPricesResponse:
        buy_history_prices = self._quoting_client.get_buy_price_points(
            self._PB_TO_STR_CURRENCIES[msg.currency],
            msg.start_timestamp, msg.end_timestamp,
            msg.interval
        )
        sell_history_prices = self._quoting_client.get_sell_price_points(
            self._PB_TO_STR_CURRENCIES[msg.currency],
            msg.start_timestamp, msg.end_timestamp,
            msg.interval
        )
        resp = v1_pb2.MsgHistoryPricesResponse(
            price_points=list(
                map(
                    lambda prices: v1_pb2.PricePoint(
                        buy_price=prices[0].price,
                        sell_price=prices[1].price,
                        timestamp=(prices[0].timestamp + prices[1].timestamp) // 2
                    ),
                    zip(buy_history_prices, sell_history_prices)
                )
            )
        )
        if len(resp.price_points) >= 2:
            price_point_most_recent = resp.price_points[0]
            price_point_oldest = resp.price_points[-1]
            avg_price_point_most_recent = (price_point_most_recent.buy_price + price_point_most_recent.sell_price) / 2
            avg_price_point_oldest = (price_point_oldest.buy_price + price_point_oldest.sell_price) / 2
            delta_price = float('{:.02f}'.format(avg_price_point_most_recent - avg_price_point_oldest))
            delta_price_perc = float('{:.02f}'.format(delta_price / avg_price_point_oldest * 100.0))
            if delta_price_perc > 0:
                trend = v1_pb2.PRICE_TREND_RISING
            elif delta_price_perc < 0:
                trend = v1_pb2.PRICE_TREND_FALLING
            else:
                trend = v1_pb2.PRICE_TREND_STAGNANT
        else:
            LOGGING_FACTORY.market.warning(
                'Could not fetch history prices, returning default price analytics')
            delta_price = delta_price_perc = 0
            trend = v1_pb2.PRICE_TREND_STAGNANT
        resp.price_analytics.trend = trend
        resp.price_analytics.delta_fiat = delta_price
        resp.price_analytics.delta_percentage = delta_price_perc

        return resp
