# -*- coding: utf-8 -*-
import os

from datetime import datetime

from application.model import UpdateType
from application.model.configuration import Configurations, CatalogConfigurations, MediaConfigurations, \
    UserConfigurations, LoaderConfigurations, BinaryConfigurations
from application.model.customexception import ConfigurationReaderException
from cfgtools import read, Configuration
from mbcontextmessagehandler import MbContextMessageBus
from messagebus import Message, DataType
from msgbus import TK_SYS_NAK, TK_STORECFG_GET
from systools import sys_parsefilepath
from ._ConfiguratorReader import ConfiguratorReader


class Configurator(object):

    def __init__(self):
        self.configs = Configurations()
        self._create_path()

        self.window_start_time = "Window.StartTime"
        self.window_end_time = "Window.EndTime"
        self.apply_window_start_time = "ApplyWindow.StartTime"
        self.apply_window_end_time = "ApplyWindow.EndTime"
        self.remote_update_window_start_time = "RemoteLoaderUpdateWindow.StartTime"
        self.remote_update_window_end_time = "RemoteLoaderUpdateWindow.EndTime"

    def get_loader_configurations(self, loader_cfg):
        # type: (str) -> None

        reader = read(loader_cfg)
        self.configs.service_name = str(reader.find_value("Identification.ComponentName"))

        def _get_config_path(key):
            return self.configs.service_name + "." + key

        self.configs.persistence_name = str(reader.find_value(_get_config_path("PersistenceName")))
        self.configs.required_services = "|".join(reader.find_values(_get_config_path("RequiredServices")))
        data_dir = sys_parsefilepath("{HVDATADIR}")
        backup_path = reader.find_value(_get_config_path("BackupDirectory"))
        self.configs.backup_directory = str(os.path.join(data_dir, backup_path))

        local_store_id = reader.find_value(_get_config_path("StoreId"))
        self.configs.store_id = str(local_store_id) if local_store_id else None

        replace_demo_info = reader.find_value(_get_config_path("ReplaceDemoInfo"), "true").lower() == "true"
        self.configs.replace_demo_info = replace_demo_info

        self.configs.updaters = {}
        self.configs.backoffice_urls = os.path.join(data_dir, "../../src/pos-updater/backoffice-urls.xml")
        path_to_catalog_json = os.path.join(
            data_dir,
            "../../genesis/data/server/databases-campaign/catalog.json",
        )
        if os.path.exists(path_to_catalog_json):
            self.configs.path_to_catalog_json = path_to_catalog_json

        if not os.path.isfile(self.configs.backoffice_urls):
            raise ConfigurationReaderException("backoffice-urls.xml not found")
        self.configs.backoffice_urls = read(self.configs.backoffice_urls)

        self._get_catalog_configurations(reader)
        self._get_media_configurations(reader)
        self._get_user_configurations(loader_cfg)
        self._get_binary_configurations(loader_cfg)
        self._get_loader_configurations(loader_cfg)

        for manager in self.configs.updaters:
            config = self.configs.updaters[manager]
            if config.enabled and config.name not in UpdateType.list_names():
                raise ConfigurationReaderException("Not supported manager: {}".format(config.name))

    def get_base_url(self, message_bus):
        # type: (MbContextMessageBus) -> None

        self.configs.base_url = self.read_sw_config(message_bus, "BackOffice.ServerURL") + "/pump"

    def get_api_key(self, message_bus):
        # type: (MbContextMessageBus) -> None

        self.configs.api_key = self.read_sw_config(message_bus, "BackOffice.ApiKey")

    def get_store_id(self, message_bus):
        # type: (MbContextMessageBus) -> None

        self.configs.store_id = self.read_sw_config(message_bus, "Store.Id")

    @staticmethod
    def read_sw_config(message_bus, key):
        # type: (MbContextMessageBus, str) -> str

        message = Message(TK_STORECFG_GET, data_type=DataType.param, data=key)
        msg = message_bus.send_message("StoreWideConfig", message)
        if msg.token == TK_SYS_NAK:
            raise ConfigurationReaderException("Unable to get Store Wide Configuration: {}".format(key))
        return str(msg.data)

    def _get_catalog_configurations(self, reader):
        # type: (Configuration) -> None

        catalog = CatalogConfigurations()
        manager_name = "Catalog"

        def _get_config(param):
            return reader.find_value(self.configs.service_name + "." + manager_name + "." + param)

        catalog.enabled = (_get_config("Enabled") or "false").lower() == "true"

        catalog.name = manager_name.lower()
        catalog.active_frequency = int(_get_config("ActiveFrequency") or 0)

        catalog.window.start_time = datetime.strptime(_get_config(self.window_start_time), "%H:%M:%S").time()
        catalog.window.end_time = datetime.strptime(_get_config(self.window_end_time), "%H:%M:%S").time()

        catalog.endpoints.get_latest_version = str(self._get_endpoint(manager_name, "getLatestVersion"))
        catalog.endpoints.download = str(self._get_endpoint(manager_name, "download"))
        catalog.endpoints.update_to = str(self._get_endpoint(manager_name, "updateTo"))

        self.configs.updaters[catalog.name] = catalog

    def _get_media_configurations(self, reader):
        # type: (Configuration) -> None

        media = MediaConfigurations()
        manager_name = "Media"

        def _get_config(param):
            return reader.find_value(self.configs.service_name + "." + manager_name + "." + param)

        media.enabled = (_get_config("Enabled") or "false").lower() == "true"

        media.name = manager_name.lower()
        media.active_frequency = int(_get_config("ActiveFrequency") or 0)

        media.images_directory = str(sys_parsefilepath(_get_config("ImagesDirectory")))

        media.window.start_time = datetime.strptime(_get_config(self.window_start_time), "%H:%M:%S").time()
        media.window.end_time = datetime.strptime(_get_config(self.window_end_time), "%H:%M:%S").time()

        image_permission_endpoint = self._get_endpoint(manager_name, "getDownloadImagePermission")
        media.endpoints.get_download_image_permission = str(image_permission_endpoint)
        media.endpoints.get_download_image_totem = str(self._get_endpoint(manager_name, "getDownloadImageTotem"))

        self.configs.updaters[media.name] = media

    def _get_user_configurations(self, loader_cfg):
        # type: (str) -> None

        user = UserConfigurations()
        manager_name = "User"
        configurator_reader = ConfiguratorReader(loader_cfg, self.configs.service_name, manager_name)

        user.enabled = (configurator_reader.get_configuration("Enabled") or "false").lower() == "true"

        user.name = manager_name.lower()
        user.active_frequency = int(configurator_reader.get_configuration("ActiveFrequency") or "0")

        start_time = configurator_reader.get_configuration(self.window_start_time)
        user.window.start_time = datetime.strptime(start_time, "%H:%M:%S").time()
        end_time = configurator_reader.get_configuration(self.window_end_time)
        user.window.end_time = datetime.strptime(end_time, "%H:%M:%S").time()

        user.endpoints.employee = str(self._get_endpoint(manager_name, "employee"))

        self.configs.updaters[user.name] = user

    def _get_loader_configurations(self, loader_cfg):
        # type: (str) -> None

        manager_name = "Loader"

        loader = LoaderConfigurations()
        loader.name = manager_name.lower()
        configurator_reader = ConfiguratorReader(loader_cfg, self.configs.service_name, manager_name)

        loader.enabled = (configurator_reader.get_configuration("Enabled") or "false").lower() == "true"
        loader.active_frequency = int(configurator_reader.get_configuration("ActiveFrequency") or "0")
        loader.remote_update_window.start_time = self._get_configuration_time(
            param=self.remote_update_window_start_time,
            config_reader=configurator_reader,
        )
        loader.remote_update_window.end_time = self._get_configuration_time(
            param=self.remote_update_window_end_time,
            config_reader=configurator_reader,
        )

        loader.window.start_time = self._get_configuration_time(
            param=self.window_start_time,
            config_reader=configurator_reader,
        )
        loader.window.end_time = self._get_configuration_time(
            param=self.window_end_time,
            config_reader=configurator_reader,
        )

        loader.endpoints.download_loaders = str(self._get_endpoint(manager_name, "loaders"))
        loader.endpoints.update_notify = self._get_endpoint(
            manager_name=manager_name,
            param="UpdateNotify",
        )

        self.configs.updaters[loader.name] = loader

    def _get_binary_configurations(self, loader_cfg):
        # type: (str) -> None

        manager_name = "Binaries"

        binary = BinaryConfigurations()
        binary.name = manager_name.lower()
        configurator_reader = ConfiguratorReader(loader_cfg, self.configs.service_name, manager_name)
        configuration = configurator_reader.get_configuration

        binary.enabled = (configuration("Enabled") or "false").lower() == "true"
        binary.active_frequency = int(configuration("ActiveFrequency") or "0")

        start_time = configuration(self.window_start_time) or "00:00:00"
        binary.window.start_time = datetime.strptime(start_time, "%H:%M:%S").time()
        end_time = configuration(self.window_end_time) or "00:00:00"
        binary.window.end_time = datetime.strptime(end_time, "%H:%M:%S").time()

        apply_start_time = configuration(self.apply_window_start_time) or "00:00:00"
        binary.apply_window.start_time = datetime.strptime(apply_start_time, "%H:%M:%S").time()
        apply_end_time = configuration(self.apply_window_end_time) or "00:00:00"
        binary.apply_window.end_time = datetime.strptime(apply_end_time, "%H:%M:%S").time()

        binary.force_update_days = int(configuration("ForceUpdateDays") or "5")
        restrict_days_update = configurator_reader.get_configuration_list("RestrictDaysUpdate") or [4, 5, 6]
        binary.restrict_days_update = [int(item) for item in restrict_days_update]

        binary.endpoints.backoffice = str(self._get_endpoint(manager_name, "Backoffice"))

        chrome_url = "https://s3.amazonaws.com/pos-install.e-deploy.com.br/chrome.zip"
        chrome_version_url = "https://s3.amazonaws.com/pos-install.e-deploy.com.br/chromeVersion.txt"
        binary.chrome_url = configuration("ChromeUrl") or chrome_url
        binary.chrome_version_url = configuration("ChromeVersionUrl") or chrome_version_url
        binary.chrome_update_enabled = (configuration("ChromeEnabled") or "false").lower() == "true"

        self.configs.updaters[binary.name] = binary

    def _get_configuration_time(
        self,           # type: Configurator
        param,          # type: str
        config_reader,  # type: ConfiguratorReader
    ):
        # type: (...) -> datetime.time

        configuration = config_reader.get_configuration(
            param=param,
            default_value="00:00:00",
        )
        return self._format_time(
            date=configuration,
        )

    def _get_endpoint(
        self,               # type: Configurator
        manager_name,       # type: str
        param,              # type: str
        default_value="",   # type: str
    ):
        # type: (...) -> str

        value = self.configs.backoffice_urls.find_value(self.configs.service_name + "." + manager_name + "." + param)
        if value is None:
            return default_value

        return value

    @staticmethod
    def _format_time(
        date,   # type: str
    ):
        # type: (...) -> datetime.time

        return datetime.strptime(date, "%H:%M:%S").time()

    @staticmethod
    def _create_path():
        data_dir = sys_parsefilepath("{HVDATADIR}")
        genesis_data = os.path.join(data_dir, "../../genesis/data")

        if not os.path.exists(genesis_data):
            os.makedirs(genesis_data)
            