from socketio import ClientNamespace as SocketIOClientNamespace
from operator import itemgetter
from switcheo.utils import stringify_message, sha1_hash_digest
import threading


class OrderBooksNamespace(SocketIOClientNamespace):
    
    def __init__(self):
        self.lock = threading.Lock()
        self.namespace = '/v2/books'
        self.order_book = {}
        SocketIOClientNamespace.__init__(self, namespace=self.namespace)
    
    def on_connect(self):
        # print("Connected to Switcheo Order Book!!")
        pass
    
    def on_disconnect(self):
        # print("Disconnected from Switcheo Order Book!!")
        pass
    
    def on_join(self):
        # print("Join Event Fired!!")
        pass
    
    def on_all(self, data):
        self.lock.acquire()
        self.order_book[data["room"]["pair"]] = data
        print("All event received: " + str(data))
        print(self.order_book.keys())
        print(self.order_book["SWTH_NEO"].keys())
        print(self.order_book["SWTH_NEO"]["book"].keys())
        self.lock.release()
        digest_hash = data["digest"]
        book = data["book"]
        book_digest_hash = sha1_hash_digest(stringify_message(book))
        print("Switcheo published SHA-1 digest hash: " + digest_hash)
        print("Python calculated SHA-1 digest hash: " + book_digest_hash)
    
    def on_updates(self, data):
        # self.order_book[data["room"]["pair"]] = data
        update_digest = data["digest"]
        update_pair = data["room"]["pair"]
        update_events = data["events"]
        self.lock.acquire()
        for event in update_events:
            price_match = False
            buy_event = False
            sell_event = False
            event_iteration = 0
            if event["side"] == "buy":
                event_side = "buys"
                buy_event = True
            elif event["side"] == "sell":
                event_side = "sells"
                sell_event = True
            event_price = event["price"]
            event_change = event["delta"]
            # order_book_event_size = len(self.order_book[update_pair]["book"][event_side])
            for side in self.order_book[update_pair]["book"][event_side]:
                if side["price"] == event_price:
                    # updated_amount = self.blockchain_amount["neo"](float(side["amount"]) + float(event_change))
                    price_match = True
                    updated_amount = int(side["amount"]) + int(event_change)
                    print(updated_amount)
                    # self.lock.acquire()
                    if updated_amount == 0:
                        self.order_book[update_pair]["book"][event_side].remove(side)
                        print("Removing Object from Array")
                    else:
                        updated_book = {}
                        updated_book["amount"] = str(updated_amount)
                        updated_book["price"] = str(event_price)
                        self.order_book[update_pair]["book"][event_side][event_iteration] = updated_book
                        print("Updating Object that exists in Array")
                        print(updated_book)
                        # print(self.order_book[update_pair]["book"][event_side])
                    # self.lock.release()
                    break
                event_iteration += 1
            if not price_match:
                new_book = {}
                new_book["amount"] = event_change
                new_book["price"] = event_price
                # self.lock.acquire()
                self.order_book[update_pair]["book"][event_side].append(new_book)
                # self.lock.release()
                print("Adding new Object to Array b/c that price doesn't exist yet.")
                print(new_book)
        if buy_event and sell_event:
            self.order_book[update_pair]["book"]["buys"] = sorted(
                self.order_book[update_pair]["book"]["buys"], key=itemgetter("price"), reverse=True)
            self.order_book[update_pair]["book"]["sells"] = sorted(
                self.order_book[update_pair]["book"]["sells"], key=itemgetter("price"), reverse=True)
        elif buy_event:
            self.order_book[update_pair]["book"]["buys"] = sorted(
                self.order_book[update_pair]["book"]["buys"], key=itemgetter("price"), reverse=True)
        elif sell_event:
            self.order_book[update_pair]["book"]["sells"] = sorted(
                self.order_book[update_pair]["book"]["sells"], key=itemgetter("price"), reverse=True)
        book = self.order_book[update_pair]["book"]
        self.lock.release()
        book_digest_hash = sha1_hash_digest(stringify_message(book))
        print("Switcheo published SHA-1 digest hash: " + update_digest)
        print("Python calculated SHA-1 digest hash: " + book_digest_hash)
        if update_digest != book_digest_hash:
            self.emit(event="leave", data=data["room"], namespace='/v2/books')
            self.emit(event="join", data=data["room"], namespace='/v2/books')
        # print("Updates event received: " + str(data))
        # print(self.order_book.keys())


class TradeEventsNamespace(SocketIOClientNamespace):

    def __init__(self):
        self.lock = threading.Lock()
        self.namespace = '/v2/trades'
        self.trade_events = {}
        SocketIOClientNamespace.__init__(self, namespace=self.namespace)

    def on_connect(self):
        print("Connected to Switcheo Trade Events!!")
        pass

    def on_disconnect(self):
        # print("Disconnected from Switcheo Trade Events!!")
        pass

    def on_join(self):
        # print("Join Event Fired!!")
        pass

    def on_all(self, data):
        self.lock.acquire()
        self.trade_events[data["room"]["pair"]] = data
        print("All event received: " + str(data))
        print(self.trade_events.keys())
        print(self.trade_events["SWTH_NEO"].keys())
        print(self.trade_events["SWTH_NEO"]["trades"][0].keys())
        self.lock.release()
        digest_hash = data["digest"]
        trades = data["trades"]
        trade_digest_hash = sha1_hash_digest(stringify_message(trades))
        print("Switcheo published SHA-1 digest hash: " + digest_hash)
        print("Python calculated SHA-1 digest hash: " + trade_digest_hash)

    def on_updates(self, data):
        update_digest = data["digest"]
        update_pair = data["room"]["pair"]
        update_events = data["events"]
        # update_events_count = len(data["events"])
        update_limit = data["limit"]
        print("Update event received: " + str(data))
        self.lock.acquire()
        self.trade_events[update_pair]["trades"] = update_events + \
            self.trade_events[update_pair]["trades"]
        trade_slice = update_limit - 1
        self.trade_events[update_pair]["trades"] = self.trade_events[update_pair]["trades"][0:trade_slice]
        # trade_events_count = len(self.trade_events[update_pair])
        # trade_events_pop = update_limit - trade_events_count - update_events_count
        # print(trade_events_pop)
        # if trade_events_pop < 0:
        #     del self.trade_events[update_pair]["trades"][trade_events_pop]
        # self.trade_events[update_pair]["trades"] = self.trade_events[update_pair]["trades"] + update_events
        # self.trade_events[update_pair]["trades"] = sorted(
        #     self.trade_events[update_pair]["trades"], key=itemgetter("timestamp"), reverse=True)
        trades = self.trade_events[update_pair]["trades"]
        self.lock.release()
        trade_digest_hash = sha1_hash_digest(stringify_message(trades))
        print("Switcheo published SHA-1 digest hash: " + update_digest)
        print("Python calculated SHA-1 digest hash: " + trade_digest_hash)
        if update_digest != trade_digest_hash:
            self.emit(event="leave", data=data["room"], namespace='/v2/trades')
            self.emit(event="join", data=data["room"], namespace='/v2/trades')


class OrderEventsNamespace(SocketIOClientNamespace):

    def __init__(self):
        self.lock = threading.Lock()
        self.namespace = '/v2/orders'
        self.order_events = {}
        SocketIOClientNamespace.__init__(self, namespace=self.namespace)

    def on_connect(self):
        print("Connected to Switcheo Order Events!!")
        pass

    def on_disconnect(self):
        # print("Disconnected from Switcheo Order Events!!")
        pass

    def on_join(self):
        # print("Join Event Fired!!")
        pass

    def on_all(self, data):
        self.lock.acquire()
        self.order_events = data
        print("All event received: " + str(data))
        print(self.order_events.keys())
        print(self.order_events.keys())
        self.lock.release()

    def on_updates(self, data):
        update_events = data["events"]
        print("Update event received: " + str(data))
        self.lock.acquire()
        self.order_events["orders"] + update_events
        self.lock.release()
