from datetime import datetime

from application.model import UpdateType, UpdateStatus
from application.model.configuration import Configurations
from application.model.customexception import ErrorInsertingNewUpdateVersion
from mbcontextmessagehandler import MbContextMessageBus
from mwhelper import BaseRepository
from persistence import Connection
from typing import Dict, Optional
from ._CommonPOSRepository import CommonPOSRepository


class MediaUpdaterPOSRepository(BaseRepository):

    def __init__(self, message_bus, configs):
        # type: (MbContextMessageBus, Configurations) -> None

        super(MediaUpdaterPOSRepository, self).__init__(message_bus.mbcontext)

        self.message_bus = message_bus
        self.configs = configs
        self.update_type = UpdateType.media
        self.update_value = self.update_type.value
        self.local_configs = configs.updaters[self.update_type.name]
        self.common_pos_repository = CommonPOSRepository(message_bus.mbcontext)

    def insert_new_media_update(self, type_id=UpdateType.media.value):
        # type: (int) -> None

        try:
            def inner_func(conn):
                # type: (Connection) -> None

                date_now = str(datetime.now().isoformat())
                query = """
                            INSERT OR REPLACE INTO UpdatesController
                            (UpdateId, UpdateName, TypeId, StatusId, ObtainedDate, DownloadedDate, BackupDate, 
                            AppliedDate, NotifiedDate)
                            VALUES (
                                (SELECT UpdateId
                                 FROM UpdatesController
                                 WHERE TypeId = 1 AND AppliedDate IS NOT NULL
                                 ORDER BY Id DESC
                                 LIMIT 1),
                                (SELECT UpdateName
                                 FROM UpdatesController
                                 WHERE TypeId = 1 AND AppliedDate IS NOT NULL
                                 ORDER BY Id DESC
                                 LIMIT 1
                                ),
                                '{0}', '{1}', '{2}', '{2}', '{2}', '{2}', '{2}'
                            )
                        """
                query_format = query.format(type_id, UpdateStatus.applied, date_now)
                conn.query(query_format)

            self.execute_with_connection(inner_func, service_name=self.configs.persistence_name)
        except Exception as ex:
            raise ErrorInsertingNewUpdateVersion(ex)

    def get_images_hashes_from_database(self):
        # type: () -> Dict[str: str]

        def inner_func(conn):
            # type: (Connection) -> Dict[str: str]

            query = "SELECT ProductCode, CustomParamValue FROM ProductCustomParams WHERE CustomParamId = 'ImageHash'"

            cursor = conn.select(query)

            images_by_hash = dict()
            for row in cursor:
                product_code = row.get_entry("ProductCode")
                guid = row.get_entry("CustomParamValue")
                images_by_hash[product_code] = guid

            return images_by_hash

        return self.execute_with_connection(inner_func)

    def get_images_hashes_from_navigation(self):
        # type: () -> Dict[str: str]

        def inner_func(conn):
            # type: (Connection) -> Dict[str: str]

            query = "SELECT NavId, CustomParamValue FROM NavigationCustomParams WHERE CustomParamId = 'ImageHash'"

            cursor = conn.select(query)

            images_by_hash = dict()
            for row in cursor:
                nav_id = row.get_entry("NavId")
                guid = row.get_entry("CustomParamValue")
                images_by_hash[nav_id] = guid

            return images_by_hash

        return self.execute_with_connection(inner_func)

    def has_already_applied_update(self):
        # type: () -> bool
        return self.common_pos_repository.has_already_applied_update(self.configs.persistence_name, self.update_value)

    def get_last_user_update_date(self):
        # type: () -> Optional[datetime]

        return self.common_pos_repository.get_last_update_date(self.configs.persistence_name, self.update_value)

    def has_pending_update_to_apply(self, type_id=UpdateType.media.value):
        # type: (int) -> bool

        def inner_func(conn):
            # type: (Connection) -> bool

            query = """
                        SELECT UpdateId
                        FROM UpdatesController
                        WHERE TypeId = '{0}' 
                          AND UpdateId = (SELECT UpdateId
                                            FROM UpdatesController
                                            WHERE TypeId = 1 AND NotifiedDate IS NOT NULL
                                            ORDER BY Id DESC
                                            LIMIT 1)
                         ORDER BY Id DESC
                         LIMIT 1
                     """.format(type_id)

            cursor = conn.select(query)
            row = cursor.get_row(0)
            return row is None

        return self.execute_with_connection(inner_func, service_name=self.configs.persistence_name)
