import pytest

from aiospb.hosts import MinMetricInfo, MinMetricInfoCache
from aiospb.nodes import Historian, Reading, ReadingStore
from aiospb.shared import DataType, DeviceKey, Metric, Quality

TS = 1000
NKEY = DeviceKey("group/node")


class A_Historian:
    def get_implementation(self) -> Historian:
        raise NotImplementedError()

    async def _should_persist_metric_history_from_a_device(self):
        historian = self.get_implementation()

        # Sanity check
        assert not await historian.load(NKEY)

        # Persist metrics
        metrics = [
            Metric(TS, 1, DataType.Int16, 1, "Integer/With Alias/Without Quality"),
            Metric(
                TS,
                "new",
                DataType.String,
                0,
                "String/Without Alias/Without Quality Good",
            ),
            Metric(
                TS, True, DataType.Boolean, 2, "Boolean/With Alias/With Quality BAD"
            ),
        ]
        metrics[1].quality = Quality.GOOD
        metrics[2].quality = Quality.BAD
        await historian.save(NKEY, metrics)
        for m in metrics:
            m.is_historical = True

        assert await historian.load(NKEY) == metrics

        # Remove history
        await historian.clear(NKEY)
        assert not await historian.load(NKEY)


class A_ReadingStore:
    def get_implementation(self) -> ReadingStore:
        raise NotImplementedError()

    async def _should_persist_readings(self):
        store = self.get_implementation()

        assert await store.get([1, 2, 3]) == [Reading.none()] * 3

        readings = [
            Reading("Metric/Integer", 1, 1, DataType.Int16),
            Reading("Metric/String", 2, "str", DataType.String),
            Reading("Metric/Boolean", 3, False, DataType.Boolean, Quality.BAD),
        ]
        await store.set(readings)

        expected = readings + [Reading("", 0, None, DataType.Unknown, Quality.BAD)]
        assert await store.get([1, 2, 3, 4]) == expected
        assert (
            await store.get(["Metric/Integer", "Metric/String", "Metric/Boolean"])
            == readings
        )


class A_MinMetricInfoCache:
    def get_implementation(self) -> MinMetricInfoCache:
        raise NotImplementedError()

    async def _should_persist_min_metric_info(self):
        cache = self.get_implementation()

        assert await cache.get(NKEY, ["Metric/Name"]) == [
            MinMetricInfo(DataType.Unknown)
        ]

        info = MinMetricInfo(DataType.Int16, 10)
        await cache.set(NKEY, {"Metric/Name": info})

        assert await cache.get(NKEY, ["Metric/Name", "no/exist"]) == [
            info,
            MinMetricInfo(DataType.Unknown),
        ]

        await cache.remove(NKEY)
        assert await cache.get(NKEY, ["Metric/Name"]) == [
            MinMetricInfo(DataType.Unknown)
        ]
