import time
from datetime import datetime, timedelta

from source.behaviors import roles
from source.behaviors.roles import base


class UndefinedRole(base.BaseRole):
    """
    Role used when the machine is looking for how it should insert itself in the network
    """

    def handle(self) -> None:
        # check if no more peers have been found
        if datetime.now() - self.manager.peer.peers.last_added >= timedelta(seconds=5):
            # SCENARIO 1 - empty network

            # filter ourselves out of the remote peers
            remote_peers = {
                address: peer
                for (address, peer) in self.manager.peer.peers.items()
                if not self.manager.communication.is_address_local(address)
            }

            # if no other peers have been found
            if len(remote_peers) == 0:
                # TODO(Faraphel): do not change the role if we already have it !!!!!! return to using undefined role just for this whole if ?
                # declare ourselves as the master of the network
                self.manager.role.current = roles.MasterRole(self.manager)
                return

            # SCENARIO 2 - network with a master

            # list all the peers considered as masters
            master_peers = {
                address: peer
                for (address, peer) in remote_peers.items()
                if peer.master
            }

            # if there is a master, become a slave
            if len(master_peers) >= 1:
                master_address, master_peer = master_peers[0]

                # declare ourselves as a slave of the network
                self.manager.role.current = roles.SlaveRole(self.manager, master_address)

            # SCENARIO 3 - network with no master

            # TODO(Faraphel): elect the machine with the lowest ping in the network
            raise NotImplementedError("Not implemented: elect the machine with the lowest ping as a master.")

        # TODO(Faraphel): calculate the expected date of the condition and wait for it
        time.sleep(1)
