#
# Aura Engine API (https://gitlab.servus.at/aura/engine-api)
#
# Copyright (C) 2020 - The Aura Engine Team.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import datetime
import requests

from enum import Enum
from models import PlayLog, PlayLogSchema, TrackSchema


class NodeType(Enum):
    """
    Types of API Server deployment models.
    """
    MAIN = "main"
    SYNC = "sync"



class ApiService():
    """
    Service handling API actions.
    """

    config = None
    logger = None
    node_type = None
    sync_host = None
    main_hosts = None


    def __init__(self, config, logger):
        """
        Initialize Service.
        """
        self.config = config
        self.logger = logger

        # Evaluate deployment mode
        node_type = NodeType.MAIN
        host_id = config.get("host_id")
        if host_id == 0:
            node_type = NodeType.SYNC

        # Configured as Sync node
        if not node_type == NodeType.MAIN:
            self.node_type = NodeType.SYNC
            self.main_hosts = [ config.get("main_host_1"), config.get("main_host_2") ]
            if not self.main_hosts[0] and not self.main_hosts[1]:
                self.logger.warn("Not a single main host defined. Be aware what you are doing.")
                msg = "No sync possible as no host nodes are configured."
            else:
                msg = "Syncing data of hosts '%s'" % (self.main_hosts)

        # Configured as Main node
        else:
            self.node_type = NodeType.MAIN
            self.sync_host = config.get("sync_host")
            if not self.sync_host:
                msg = "No child node for synchronization defined."
            else:
                msg = "Pushing data to '%s'" % (self.sync_host)

        self.logger.info("Running in '%s' mode. %s" % (self.node_type, msg))



    def current_track(self):  
        """
        Retrieves the currently playing track.  

        Returns:
            (PlayLogEntry)
        """
        track = PlayLog.select_current()
        track_schema = TrackSchema()
        return track_schema.dump(track)


    def list_tracks(self, page=None, size=None):  
        """
        Lists track-service entries with pagination.

        Args:
            page (Integer): The number of the page to return
            size (Integer): The numbers of items to return

        Returns:
            (List[PlayLogEntry])
        """
        if not size or size > 50 or size < 1: size = 20
        tracklist = PlayLog.paginate(page, size, None)
        tracklist_schema = TrackSchema(many=True)
        return tracklist_schema.dump(tracklist)


    def list_playlog(self, page=None, size=None, since_time=None):  
        """
        Get paginated playlog entries for since the given timestamp.  

        Args:
            page (Integer): The number of items to skip before starting to collect the result set
            size (Integer): The numbers of items to return per page
            since_time (datetime): Optionally, get entries after this timestamp (e.g. "2020-08-29T09:12:33.001Z")

        Returns:
            (List[PlayLogEntry])
        """
        tracklist = PlayLog.paginate(page, size, since_time)
        tracklist_schema = TrackSchema(many=True)
        return tracklist_schema.dump(tracklist)


    def store_playlog(self, data): 
        """
        Stores the passed playlog entry.

        Returns:
            (PlayLogEntry)
        """
        if not data.log_source:
            data.log_source = self.host_id

        playlog = PlayLog(data)
        playlog.save()
        self.logger.debug("Stored playlog for '%s'" % playlog.track_start)

        # Main Node: Push to Sync Node, if enabled
        if self.node_type = NodeType.MAIN and self.sync_host:
            playlog_schema = PlayLogSchema()
            json_playlog = playlog_schema.dump(playlog)

            try:
                api_url = self.sync_host + self.config.get("sync_api_store_playlog")
                r = requests.post(api_url, json=json_playlog)
                if r.status_code == 200:
                    self.logger.info("Successfully pushed playlog for '%s' to '%s'" % (playlog.track_start, self.sync_host))
                    playlog.is_synced = True
                    playlog.save()
                else:
                    self.logger.error("Error while pushing playlog to sync-node: " + r.json())
            except Exception as e:
                self.logger.error("Error while posting to sync-node API '%s'!" % (api_url), e)

        
    def clock_info(self):
        """
        Retrieves the currently playing playlist.  
        """
        return "current playlist"


    def activate_engine(self, engine_number):
        """
        Activates one engine and deactivates the other

        Args:
            engine_number (Integer): Number of the engine
        """
        return 'do some magic!'


    def get_active_engine(self):
        """
        Retrieves the status entry of the currently active engine

        Returns:
            StatusEntry
        """
        return 'do some magic!'


    def get_engine_health(self, engine_number):
        """
        Retrieves the most recent health info of the requested engine

        Args:
            engine_number (Integer): Number of the engine


        Returns:
            (HealthInfo)
        """
        return 'do some magic!'


    def log_engine_health(self, engine_number):
        """
        Logs another health entry for the given engine

        Args:
            engine_number (Integer): Number of the engine

        """
        return 'do some magic!'