import logging
from datetime import datetime
from typing import List

import pytz
from sqlalchemy import select, and_

from peek_plugin_diagram._private.storage.DispIndex import DispIndexerQueue
from peek_plugin_diagram._private.storage.LiveDbDispLink import LiveDbDispLink
from peek_plugin_diagram._private.storage.ModelSet import (
    ModelSetTable,
    ModelCoordSetTable,
)
from peek_plugin_diagram._private.worker.tasks.LiveDbDisplayValueConverter import (
    LiveDbDisplayValueConverter,
)
from peek_plugin_livedb.tuples.LiveDbDisplayValueTuple import (
    LiveDbDisplayValueTuple,
)

logger = logging.getLogger(__name__)


class WorkerApiImpl:
    """Worker Api

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

    """

    _FETCH_SIZE = 5000

    @classmethod
    def updateLiveDbDisplayValues(
        cls,
        ormSession,
        modelSetKey: str,
        liveDbRawValues: List[LiveDbDisplayValueTuple],
    ) -> None:
        if not liveDbRawValues:
            return

        startTime = datetime.now(pytz.utc)

        modelSetId = (
            ormSession.query(ModelSetTable.id)
            .filter(ModelSetTable.key == modelSetKey)
            .one()
            .id
        )

        translater = LiveDbDisplayValueConverter.create(ormSession, modelSetId)

        for item in liveDbRawValues:
            if item.dataType is None:
                logger.warning("LiveDB key %s is missing dataType", item.key)
                continue

            item.displayValue = translater.translate(
                item.dataType, item.rawValue
            )

        logger.debug(
            "Converted %s LiveDB Raw Values in %s",
            len(liveDbRawValues),
            (datetime.now(pytz.utc) - startTime),
        )

    @classmethod
    def liveDbDisplayValueUpdateNotify(
        cls, ormSession, modelSetKey: str, updatedKeys: List[str]
    ):
        logger.debug("TODO TODO - liveDbDisplayValueUpdateNotify coordSetId")
        linkTable = LiveDbDispLink.__table__
        coordSetTable = ModelCoordSetTable.__table__
        queueTable = DispIndexerQueue.__table__

        modelSetId = (
            ormSession.query(ModelSetTable.id)
            .filter(ModelSetTable.key == modelSetKey)
            .one()
            .id
        )

        stmt = (
            select(linkTable.c.dispId)
            .select_from(
                linkTable.join(
                    coordSetTable, linkTable.c.coordSetId == coordSetTable.c.id
                )
            )
            .where(
                and_(
                    linkTable.c.liveDbKey.in_(updatedKeys),
                    coordSetTable.c.modelSetId == modelSetId,
                )
            )
        )

        ins = queueTable.insert().from_select(["dispId"], stmt)
        ormSession.execute(ins)
