import unittest

from v20.pricing import ClientPrice
from v20.pricing_common import PriceBucket as OandaPriceBucket

from algo.constant import Symbol
from algo.data.common import PriceBucket, PricePoint, CompletePricePoint
from algo.util import str_to_dt

STATIC_TIME_STR = "2022-08-26T20:58:01.403692247Z"
STATIC_TIME = str_to_dt(STATIC_TIME_STR)
STATIC_PRICE_ASK = 137.558
STATIC_PRICE_BID = 137.497

INSTRUMENT_STR = 'GBP_USD'
INSTRUMENT_SYMBOL = Symbol(INSTRUMENT_STR)

ASK_PRICE_BUCKETS_DATA = [
    {
        "price": 137.553,
        "liquidity": 1000000
    }, {
        "price": 137.555,
        "liquidity": 2000000
    }]

ASK_BUCKETS = [OandaPriceBucket(**data) for data in ASK_PRICE_BUCKETS_DATA]

BID_PRICE_BUCKETS_DATA = [
    {
        "price": 137.502,
        "liquidity": 1000000
    }, {
        "price": 137.5,
        "liquidity": 2000000
    }, {
        "price": 137.499,
        "liquidity": 2000000
    }
]

BID_BUCKETS = [OandaPriceBucket(**data) for data in BID_PRICE_BUCKETS_DATA]


class TestPricePoint(unittest.TestCase):

    def test_is_valid_price_data(self):
        self.assertTrue(
            PricePoint.is_valid_price_data(
                ClientPrice(
                    time=STATIC_TIME_STR,
                    closeoutBid=STATIC_PRICE_BID,
                    closeoutAsk=STATIC_PRICE_ASK)
            )
        )
        self.assertFalse(PricePoint.is_valid_price_data(
            ClientPrice()
        ))

    def test_from_oanda_price(self):
        self.assertEqual(
            PricePoint.from_oanda_price(
                ClientPrice(
                    time=STATIC_TIME_STR,
                    closeoutBid=STATIC_PRICE_BID,
                    closeoutAsk=STATIC_PRICE_ASK)
            ),
            PricePoint(STATIC_TIME, STATIC_PRICE_ASK, STATIC_PRICE_BID)
        )


class TestCompletePricePoint(unittest.TestCase):

    def test_is_valid_price_data(self):
        self.assertTrue(
            CompletePricePoint.is_valid_price_data(
                ClientPrice(
                    time=STATIC_TIME_STR,
                    closeoutBid=STATIC_PRICE_BID,
                    closeoutAsk=STATIC_PRICE_ASK)
            )
        )
        self.assertFalse(CompletePricePoint.is_valid_price_data(
            ClientPrice()
        ))

    def test_from_oanda_price(self):
        def _price_bucket_from_dict(data: dict) -> PriceBucket:
            return PriceBucket(data['price'], data['liquidity'])

        self.assertEqual(
            CompletePricePoint.from_oanda_price(
                ClientPrice(
                    time=STATIC_TIME_STR,
                    instrument=INSTRUMENT_STR,
                    closeoutBid=STATIC_PRICE_BID,
                    closeoutAsk=STATIC_PRICE_ASK,
                    asks=ASK_BUCKETS,
                    bids=BID_BUCKETS
                )
            ),
            CompletePricePoint(
                STATIC_TIME, INSTRUMENT_SYMBOL, STATIC_PRICE_ASK, STATIC_PRICE_BID, [
                    _price_bucket_from_dict(d) for d in ASK_PRICE_BUCKETS_DATA
                ],
                [
                    _price_bucket_from_dict(d) for d in BID_PRICE_BUCKETS_DATA
                ]
            )
        )


class TestPriceBucket(unittest.TestCase):
    def test_test_case_can_differ(self):
        self.assertNotEqual(
            PriceBucket(11.2, 1000),
            PriceBucket(22.2, 2000),
        )

    def test_kwargs_work_as_expected(self):
        self.assertEqual(
            PriceBucket(11.2, 1000),
            PriceBucket(liquidity=1000, price=11.2),
        )
