# future imports
from __future__ import absolute_import
from __future__ import unicode_literals

# stdlib imports
import logging
import time

from mopidy import core

import paho.mqtt.client as mqtt

# third-party imports
import pykka

logger = logging.getLogger(__name__)

class MQTTFrontend(pykka.ThreadingActor, core.CoreListener):

    def __init__(self, config, core):
        logger.info("Initializing ... ")
        self.core = core
        self.mqttClient = mqtt.Client(client_id="mopidy-" + str(int(round(time.time() * 1000))), clean_session=True)
        self.mqttClient.on_message = self.mqtt_on_message
        self.mqttClient.on_connect = self.mqtt_on_connect     
        
        self.config = config['mqtthook']
        host = self.config['mqtthost']
        port = self.config['mqttport']
        self.stoppedImage = self.config['stoppedimage']
        self.defaultImage = self.config['defaultimage']
        self.topic = self.config['topic']
        if self.config['username'] and self.config['password']:
            self.mqttClient.username_pw_set(self.config['username'], password=self.config['password'])
        self.mqttClient.connect_async(host, port, 60)        
        
        self.mqttClient.loop_start()
        super(MQTTFrontend, self).__init__()
        self.MQTTHook = MQTTHook(self, core, config, self.mqttClient)
        
    def mqtt_on_connect(self, client, userdata, flags, rc):
        logger.info("Connected with result code %s" % rc)
        for sub in ["/play","/control","/volume","/info","/search"]:
            rc = self.mqttClient.subscribe(self.topic+sub)
            if rc[0] != mqtt.MQTT_ERR_SUCCESS:
                logger.warn("Error during subscribe: " + str(rc[0]))
            else:              
                logger.info("Subscribed to " + self.topic + sub)

    def mqtt_on_message(self, mqttc, obj, msg):
        payload = msg.payload.decode()
        logger.info("received a message on " + msg.topic+" with payload " + payload)
        topPlay = self.topic + "/play"
        topControl = self.topic + "/control"
        topVolume = self.topic + "/volume"
        topInfo = self.topic + "/info"
        topSearch = self.topic + "/search"

        if msg.topic == topPlay:
            self.core.tracklist.clear()
            self.core.tracklist.add(uris=[payload])
            self.core.playback.play()
        elif msg.topic == topControl:
            if payload == "stop":
                self.core.playback.stop()
            elif payload == "pause":
                self.core.playback.pause()
            elif payload == "play":
                self.core.playback.play()
            elif payload == "resume":
                self.core.playback.resume()
            elif payload == "next":
                self.core.playback.next()
            elif payload == "previous":
                self.core.playback.previous()
            elif payload == "volplus":
                vol=self.core.mixer.get_volume().get()+10
                if (vol>100):
                    vol=100
                self.core.mixer.set_volume(vol)
            elif payload == "volminus":
                vol=self.core.mixer.get_volume().get()-10
                if (vol<0):
                    vol=0
                self.core.mixer.set_volume(vol)

        elif msg.topic == topVolume:
            try:
                volume=int(msg.payload)
                self.core.mixer.set_volume(volume)
            except ValueError:
                logger.warn("invalid payload for volume: " + msg.payload)
        elif msg.topic == topInfo:
            if msg.payload == "volume":
                self.MQTTHook.publish("/info","volume;"+str(self.core.mixer.get_volume().get()))
            elif msg.payload == "list":
                plist=self.core.playlists.as_list()
                for a in plist.get():
                    self.MQTTHook.publish("/lists","%s;%s"%(a.name,a.uri) )
        elif msg.topic == topSearch:
            search=msg.payload.replace("de ","")
            res=self.core.library.search({'any': [search]},uris=['local:']).get()
            found=(len(res[0].tracks))
            logger.info("Adding %d tunes from %s"%(found,search))
            
            if (found>0):
                self.core.tracklist.clear()
                self.core.tracklist.add(tracks=res[0].tracks)
                self.MQTTHook.publish("/state","Adding %d tunes from %s"%(found,search))
                self.core.mixer.set_volume(7)
                self.core.playback.play()


    def on_stop(self):
        logger.info("mopidy_mqtt shutting down ... ")
        self.mqttClient.disconnect()
        
    def stream_title_changed(self, title):
        logger.info("before" + title)
        titleStripped = title.rstrip('.mp3')
        logger.info("after" + titleStripped)
        self.MQTTHook.publish("/nowplaying", titleStripped)

    def playback_state_changed(self, old_state, new_state):
        self.MQTTHook.publish("/state", new_state)
        if (new_state == "stopped"):
            self.MQTTHook.publish("/nowplaying", "stopped")
            self.MQTTHook.publish("/image", self.stoppedImage)
            
        
    def track_playback_started(self, tl_track):
        track = tl_track.track
        artists="unknown"
        if (len(track.artists)>0):
            artists = ', '.join(sorted([a.name for a in track.artists]))
        if (track.name is None):
            tn="stream"
        else:
            tn=track.name
        tn = tn.rstrip('.mp3')
        self.MQTTHook.publish("/nowplaying", artists + ":" + tn)
        imageUri=self.core.library.get_images([track.uri]).get()[track.uri]
        if (imageUri):
          self.MQTTHook.publish("/image", imageUri[0].uri)
        else:
          self.MQTTHook.publish("/image", self.defaultImage)
        
class MQTTHook():
    def __init__(self, frontend, core, config, client):
        self.config = config['mqtthook']        
        self.mqttclient = client
       
    def publish(self, topic, state):
        full_topic = self.config['topic'] + topic
        try:
            rc = self.mqttclient.publish(full_topic, state)
            if rc[0] == mqtt.MQTT_ERR_NO_CONN:            
                logger.warn("Error during publish: MQTT_ERR_NO_CONN")
            else:
                logger.info("Sent " + state + " to " + full_topic)
        except Exception as e:
            logger.error('Unable to send', exc_info=True)