#!/usr/bin/env python3
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.

import json
import logging
import traceback


from ops.main import main
from ops.charm import CharmBase
from ops.model import ActiveStatus


logger = logging.getLogger(__name__)


class VnfPolicyCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)

        # Charm events
        self.framework.observe(self.on.install, self._on_install)
        self.framework.observe(self.on.add_user_action, self._on_add_user_action)

    def _on_install(self, _):
        import subprocess
        subprocess.run(["apt", "install", "python3.8", "-y"])
        subprocess.run(["rm", "/usr/bin/python3"])
        subprocess.run(["ln", "-s", "/usr/bin/python3.8", "/usr/bin/python3"])
        self.unit.status = ActiveStatus()

    def _on_add_user_action(self, event):
        """Add user action."""
        from ns import NetworkService
        err = ""
        output = ""
        try:
            username = event.params["username"]
            bw = event.params.get("bw")
            qos = event.params.get("qos")
            tariff = event.params.get("tariff")

            client = NetworkService(
                user=self.config["juju-username"],
                secret=self.config["juju-password"],
            )

            user_id = self._add_user(client, username, tariff)
            if user_id > 0:
                success = self._set_policy(client, user_id, bw, qos)
            else:
                logger.debug("user_id is 0; add_user failed.")

            logger.debug("Output from charm: {}".format(output))
            event.set_results(
                {
                    "user-id": user_id,
                    "policy-set": success,
                }
            )
        except Exception as err:
            logger.error(str(err))
            logger.debug(str(traceback.format_exc()))
            event.fail(str(err))


    def _add_user(self, client, username, tariff):
        """Add a user to the database and return the id."""

        ns_config_info = json.loads(self.config["ns_config_info"])

        application = ns_config_info["osm-config-mapping"][
            "{}.{}.{}".format(
                "1",  # member-vnf-index
                "userVM",  # vdu_id
                "0",  # vdu_count_index
            )
        ]

        output = client.ExecutePrimitiveGetOutput(
            # The name of the application for adding a user
            application,
            # The name of the action to call
            "add-user",
            # The parameter(s) required by the above charm and action
            params={
                "username": username,
                "tariff": tariff,
            },
            # How long to wait (in seconds) for the action to finish
            timeout=500,
        )

        # Get the output from the `add-user` function
        user_id = int(output["user-id"])
        return user_id


    def _set_policy(self, client, user_id, bw, qos):
        """Set the policy for a user."""
        success = False

        ns_config_info = json.loads(self.config["ns_config_info"])

        application = ns_config_info["osm-config-mapping"][
            "{}.{}.{}".format(
                "2",  # member-vnf-index
                "policyVM",  # vdu_id
                "0",  # vdu_count_index
            )
        ]

        success = client.ExecutePrimitiveGetOutput(
            # The name of the application for policy management
            application,
            # The name of the action to call
            "set-policy",
            # The parameter(s) required by the above charm and action
            params={
                "user_id": user_id,
                "bw": bw,
                "qos": qos,
            },
            # How long to wait (in seconds) for the action to finish
            timeout=500,
        )

        # Get the output from the `add-user` function
        return success.get("updated", False)


if __name__ == "__main__":
    main(VnfPolicyCharm)
