from flask_socketio import emit
from models.User import User
from models.Device import Device
from config.webrtc import EXPIRY, SECRET_KEY
from config.database import db
import time
import hashlib
import hmac


class SocketUser:
    sid = None
    connected = True
    authenticated = False
    token = None
    client_id = None
    is_device = False
    webrtc_username = ""
    webrtc_password = ""
    webrtc_credentials_valididity = 0

    def __init__(self, sid):
        self.sid = sid

    def __str__(self):
        return '<SocketClient(' + str(self.client_id) + ', ' + str(self.sid) + ')/>'

    @staticmethod
    def construct_client(client_id, is_device, data):
        if data is not None:
            client = SocketUser(data["sid"])
            client.client_id = client_id
            client.is_device = is_device
            client.connected = True if data["co"] == "True" else False
            client.authenticated = True if data["auth"] == "True" else False
            client.token = data["token"]
            client.webrtc_username = data["wu"]
            client.webrtc_password = data["wp"]
            client.webrtc_credentials_valididity = int(data["wcv"])
            return client
        return None

    def get_payload(self):
        return {"sid": self.sid, "co": self.connected, "auth": self.authenticated, "token": self.token,
                "wu": self.webrtc_username, "wp": self.webrtc_password,
                "wcv": self.webrtc_credentials_valididity}

    def get_key(self):
        if self.client_id is None:
            return None
        return ("d" if self.is_device else "u") + str(self.client_id)

    def generate_credentials(self):
        validity = time.time() + EXPIRY
        self.webrtc_username = str(validity) + ':' + str(self.client_id) + str(self.is_device)
        digest_maker = hmac.new(SECRET_KEY.encode('utf-8'), b'', hashlib.sha1)
        digest_maker.update(self.webrtc_username.encode('utf-8'))
        self.webrtc_password = str(digest_maker.digest())
        self.webrtc_credentials_valididity = validity
        return self.webrtc_username, self.webrtc_password

    def get_client(self):
        client = None
        if self.client_id is not None:
            if self.is_device:
                client = db.session.query(Device).filter(Device.id == self.client_id).first()
            else:
                client = db.session.query(User).filter(User.id == self.client_id).first()
        return client

    def authenticate(self, jwt_token):
        try:
            if self.authenticated is True:
                return False, "Already authenticated"
            b, client = User.decode_auth_token_old(jwt_token)
            if not b:
                b, client = Device.decode_auth_token_old(jwt_token)
                if b:
                    self.is_device = True
            if not b or client is None:
                return False, 'User not found'
            if client.json_token != jwt_token:
                return False, 'Invalid token'
            self.token = jwt_token
            self.client_id = client.id
            client.update_content(is_online=True)
            self.authenticated = True
            return True, 'User authenticated'
        except Exception as e:
            return False, str(e)

    def emit(self, event, data, namespace='/', room=None):
        if room is None:
            room = self.sid
        emit(event, data, room=room, namespace=namespace)

    def disconnect(self):
        if self.authenticated:
            client = self.get_client()
            if client is not None:
                client.update_content(is_online=False)

    def get_content(self):
        return {
            'sid': self.sid,
            'authenticated': self.authenticated,
            'client': self.client_id,
            'connected': self.connected,
            'is_device': self.is_device
        }
