#!/usr/bin/env python3

import logging
import mitel_ommclient2
import time

logger = logging.getLogger("fieldpoc.dect")

class Dect:
    def __init__(self, fp):
        self.fp = fp

    def _init_client(self):
        self.c = mitel_ommclient2.OMMClient2(
            host=self.fp.config.dect.host,
            username=self.fp.config.dect.username,
            password=self.fp.config.dect.password,
            ommsync=True,
        )

    def get_temp_number(self):
        temp_num_prefix = next(self.fp.extensions.extensions_by_type("temp")).num
        current_temp_extension = 0
        used_temp_extensions = [u.num[len(temp_num_prefix):] for u in self.c.find_users(lambda u: u.num.startswith(temp_num_prefix))]

        while "{:0>4}".format(current_temp_extension) in used_temp_extensions:
            current_temp_extension += 1

        return "{}{:0>4}".format(temp_num_prefix, current_temp_extension)

    def get_sip_password_for_number(self, num):
        return num

    def create_and_bind_user(self, d, num):
        u = self.c.create_user(num)
        self.c.attach_user_device(u.uid, d.ppn)
        self.c.set_user_relation_fixed(u.uid)
        self.c.set_user_sipauth(u.uid, num, self.get_sip_password_for_number(num))

    def run(self):
        logger.info("initialising connection to OMM")
        self._init_client()

        while True:
            msg = self.fp.queues["dect"].get()
            self.fp.queues["dect"].task_done()

            if msg.get("type") == "stop":
                break
            elif msg.get("type") == "sync":
                logger.info("syncing")

                extensions = self.fp.extensions.extensions_by_type("dect")
                extensions_by_num = {e.num: e for e in extensions}
                extensions_by_ipei = {e._c['dect_ipei']: e for _, e in extensions_by_num.items() if e._c.get('dect_ipei')}

                users_by_ext = {}
                users_by_uid = {}
                for user in self.c.get_users():
                    e = extensions_by_num.get(user.num)
                    if not e:
                        # user in omm, but not as dect in nerd
                        # TODO: delete in omm
                        if user.num.startswith(next(self.fp.extensions.extensions_by_type("temp")).num):
                            users_by_ext[user.num] = user
                            users_by_uid[user.uid] = user
                        continue
                    elif e._c['name'] != user.name:
                        self.c.set_user_name(user.uid, e._c['name'])
                    if e._c.get('dect_ipei') and user.relType != mitel_ommclient2.types.PPRelTypeType("Unbound"):
                        d = self.c.get_device(user.ppn)
                        if d.ipei != e._c['dect_ipei']:
                            logger.debug(f"Detaching {user} {d}")
                            self.c.detach_user_device(user.uid, user.ppn)

                    self.c.set_user_sipauth(user.uid, e.num, self.get_sip_password_for_number(e.num))
                    users_by_ext[user.num] = user
                    users_by_uid[user.uid] = user

                for d in self.c.get_devices():
                    e = extensions_by_ipei.get(d.ipei)
                    if e:
                        # device is in nerd
                        u = users_by_ext.get(e.num)
                        if u and d.relType == mitel_ommclient2.types.PPRelTypeType("Unbound"):
                            logger.debug(f'Binding user for {d}')
                            self.c.attach_user_device(u.uid, d.ppn)
                            self.c.set_user_relation_fixed(u.uid)
                        elif d.relType != mitel_ommclient2.types.PPRelTypeType("Unbound"):
                            ui = users_by_uid.get(d.uid)
                            if ui.num != e.num:
                                logger.debug(f'User for {d} has wrong number')
                                self.c.set_user_num(d.uid, e.num)
                                self.c.set_user_sipauth(d.uid, e.num, self.get_sip_password_for_number(e.num))
                        else:
                            logger.debug(f'Creating and binding user for {d}')
                            self.create_and_bind_user(d, e.num)

                    elif d.relType == mitel_ommclient2.types.PPRelTypeType("Unbound"):
                        temp_num = self.get_temp_number()
                        logger.debug(f'Creating and binding tmp-user for {d}: {temp_num}')
                        self.create_and_bind_user(d, temp_num)

        self.c.connection.close()