from .task import task, Form, FormParameter, FormValidator, FormFilling, TaskRunner
from .responses import unauthorized
from .scan import scan, ScanRunner


class StatusRunner(TaskRunner):
    """
    Collects info on the node's status.
    """

    def enter_access_pw(self, form):
        """

        :param form: CredentialsForm
        :return:
        """
        raise NotImplementedError()

    def on_status(self, local_revision_nb, hub_revision_nb, local_changes):
        """
        Called when the status was collected.

        :param local_revision_nb: the node's revision number
        :type local_revision_nb: int
        :param hub_revision_nb: the hub's revision number
        :type hub_revision_nb: int
        :param local_changes: a list of actions that represent changes in the node's collection since the last revision
        :type local_changes: list of Action
        """
        raise NotImplementedError()


class CredentialsForm(Form):
    def __init__(self):
        super().__init__()
        self.access_pw = FormParameter(self)
        self.access_pw_is_correct = FormValidator(self.access_pw)


@task
def status(runner, node_db, access_pw):
    credentials = CredentialsForm()

    @FormFilling(input_func=runner.enter_access_pw, forms=credentials)
    def work():
        resp = runner.request(
            url="{}/revision".format(node_db.hub_url),
            data=dict(access_pw=access_pw)
        )
        if resp.match(unauthorized):
            credentials.access_pw_is_correct.fail()

        scan(runner=ScanRunner(), db=node_db)  # TODO allow for ScanRunner callbacks

        runner.on_status(
            local_revision_nb=node_db.revision_nb,
            hub_revision_nb=int(resp.text),
            local_changes=node_db.get_local_changes()
        )
