from typing import List, Dict

from sqlalchemy import select

from peek_plugin_base.storage.StorageUtil import (
    makeCoreValuesSubqueryCondition,
    makeOrmValuesSubqueryCondition,
)
from peek_plugin_livedb._private.storage.LiveDbItem import LiveDbItem
from peek_plugin_livedb._private.storage.LiveDbModelSet import (
    LiveDbModelSet,
    getOrCreateLiveDbModelSet,
)
from peek_plugin_livedb.tuples.LiveDbDisplayValueTuple import (
    LiveDbDisplayValueTuple,
)
from peek_plugin_livedb.tuples.LiveDbRawValueTuple import LiveDbRawValueTuple


class WorkerApi:
    """Worker Api

    This class allows other classes to work with the LiveDB plugin on the
    worker service.

    """

    _FETCH_SIZE = 5000

    @classmethod
    def getLiveDbDisplayValues(
        cls, ormSession, modelSetKey: str, liveDbKeys: List[str]
    ) -> List[LiveDbDisplayValueTuple]:
        """Get Live DB Display Values

        Return an array of items representing the display values from the LiveDB.

        :param ormSession: The SQLAlchemy orm session from the calling code.
        :param modelSetKey: The name of the model set to get the keys for
        :param liveDbKeys: An array of LiveDb Keys.

        :returns: An array of tuples.
        """
        if not liveDbKeys:
            return []

        liveDbModelSet = getOrCreateLiveDbModelSet(ormSession, modelSetKey)

        liveDbKeys = set(liveDbKeys)  # Remove duplicates if any exist.
        qry = (
            ormSession.query(LiveDbItem)
            .filter(LiveDbItem.modelSetId == liveDbModelSet.id)
            .filter(
                makeOrmValuesSubqueryCondition(
                    ormSession, LiveDbItem.key, list(liveDbKeys)
                )
            )
            .yield_per(cls._FETCH_SIZE)
        )

        results = []

        for item in qry:
            results.append(
                LiveDbDisplayValueTuple(
                    key=item.key,
                    displayValue=item.displayValue,
                    rawValue=item.rawValue,
                    dataType=item.dataType,
                )
            )

        return results
