# -*- coding: utf-8 -*-
from __future__ import print_function
import json
import thread
import time
from socket import error as socket_error

import paho.mqtt.client as mqtt

from pokemongo_bot.event_manager import EventHandler

DEBUG_ON = False


class MyMQTTClass:
    MAX_RESULTS = 50

    def __init__(self, bot, clientid=None):
        self.bot = bot
        self.client_id = clientid
        self.bot.mqtt_pokemon_list = []
        self._mqttc = None

    def mqtt_on_connect(self, mqttc, obj, flags, rc):
        if rc is 0:
            self._mqttc.subscribe("pgo/#", 1)
        if DEBUG_ON:
            print("rc: " + str(rc))

    def mqtt_on_message(self, mqttc, obj, msg):
        if DEBUG_ON:
            print('on message: {}'.format(msg.payload))

        pokemon = json.loads(msg.payload)
        if pokemon and 'encounter_id' in pokemon:
            new_list = [x for x in self.bot.mqtt_pokemon_list if x['encounter_id'] is pokemon['encounter_id']]
            if not (new_list and len(new_list) > 0):
                if len(self.bot.mqtt_pokemon_list) > self.MAX_RESULTS:
                    del self.bot.mqtt_pokemon_list[:]
                self.bot.mqtt_pokemon_list.append(pokemon)

    def on_disconnect(self, client, userdata, rc):
        self._mqttc.unsubscribe("pgo/#")
        if DEBUG_ON:
            print('on_disconnect')
            if rc != 0:
                print("Unexpected disconnection.")

    def mqtt_on_publish(self, mqttc, obj, mid):
        if DEBUG_ON:
            print("mid: " + str(mid))

    def mqtt_on_subscribe(self, mqttc, obj, mid, granted_qos):
        if DEBUG_ON:
            print("Subscribed: " + str(mid) + " " + str(granted_qos))

    # def mqtt_on_log(self, mqttc, obj, level, string):
    #    print string

    def publish(self, channel, message):
        if self._mqttc:
            try:
                self._mqttc.publish(channel, message)
            except UnicodeDecodeError:
                pass

    def initialize(self):
        try:
            if DEBUG_ON:
                print('connect again')

            self._mqttc = mqtt.Client(None)
            self._mqttc.on_message = self.mqtt_on_message
            self._mqttc.on_connect = self.mqtt_on_connect
            self._mqttc.on_subscribe = self.mqtt_on_subscribe
            self._mqttc.on_publish = self.mqtt_on_publish
            self._mqttc.on_disconnect = self.on_disconnect

            # Enable this line if you are doing the snip code, off stress
            # self._mqttc.loop_start()
        except TypeError:
            print('Connect to mqtter error')
            return

    def run(self):
        try:
            self._mqttc.connect("broker.pikabot.org", 1883, 20)
        except:
            print('Error occured in social handler')
        while True:
            try:
                self._mqttc.loop_forever(timeout=30.0, max_packets=100, retry_first_connection=False)
                print('Oops disconnected ?')
                time.sleep(20)
            except UnicodeDecodeError:
                time.sleep(1)
            except Exception as e:
                print(e)
                time.sleep(10)


class SocialHandler(EventHandler):
    def __init__(self, bot):
        super(SocialHandler, self).__init__()
        self.bot = bot
        self.mqttc = None

    def handle_event(self, event, sender, level, formatted_msg, data):
        if self.mqttc is None:
            try:
                if DEBUG_ON:
                    print('need connect')

                self.mqttc = MyMQTTClass(self.bot, self.bot.config.client_id)
                self.mqttc.initialize()
                self.bot.mqttc = self.mqttc
                thread.start_new_thread(self.mqttc.run)
            except socket_error as serr:
                # if serr.errno == errno.ECONNREFUSED:
                # ECONNREFUSED
                self.mqttc = None
                return

        if event == 'catchable_pokemon' and 'pokemon_id' in data:
            # self.mqttc.publish("pgomapcatch/all", str(data))
            # self.mqttc.publish("pgomapcatch/all/catchable/"+str(data['pokemon_id']), str(data))
            # precision=4 mean 19545 meters, http://stackoverflow.com/questions/13836416/geohash-and-max-distance
            # geo_hash = Geohash.encode(data['latitude'], data['longitude'], precision=4)
            # self.mqttc.publish("pgomapgeo/"+geo_hash+"/"+str(data['pokemon_id']), str(data['latitude'])+","+str(data['longitude'])+","+str(data['encounter_id'])+","+str(data['pokemon_id'])+","+str(data['expiration_timestamp_ms'])+","+str(data['pokemon_name']))
            # {u'pokemon_id': 13, u'expiration_timestamp_ms': 1472017713812L, u'longitude': 4.897220519201337, u'latitude': 52.33937206069979, u'spawn_point_id': u'47c60a241ad', u'encounter_id': 13653280540966083917L}
            data_string = "%s, %s, %s, %s, %s" % (
            str(data['latitude']), str(data['longitude']), str(data['pokemon_id']),
            str(data['expiration_timestamp_ms']), str(data['pokemon_name']))
            self.mqttc.publish("pgomapcatch/all/catchable/" + str(data['pokemon_id']), data_string)
            json_data = json.dumps(data)
            self.mqttc.publish("pgo/all/catchable/" + str(data['pokemon_id']), json_data)