from bundlewrap.exceptions import BundleError
from bundlewrap.items import Item


def backend_segments_to_dict(segments):
    attributes = {}

    name = segments[0].strip()

    attributes["backend"] = segments[1].strip().rstrip(",")

    attributes["port"] = None

    if ":" in attributes["backend"]:
        backend_segments = attributes["backend"].split(":")
        attributes["backend"] = backend_segments[0]
        attributes["port"] = int(backend_segments[1])

    attributes["remove_prefix"] = None

    flag = segments[2]
    if flag == "--remove-prefix":
        attributes["remove_prefix"] = True

    return attributes

def get_backend_config(node, name):
    result = node.run("uberspace web backend list", may_fail=True)
    backend_lines = result.stdout_text.splitlines()

    for line in backend_lines:
        segments = line.split("=>", 1)[0].strip().split(" ")
        if segments[0] == name:
            d = backend_segments_to_dict(segments)
            return d

def make_display_string(name, attributes):
    backend_name = attributes.get("backend")
    if attributes.get("backend") == "http":
        backend_name += f":{attributes.get('port')}"

    args = [ backend_name ]

    if attributes["remove_prefix"]:
        args.append("--remove-prefix")

    arg_string = ", ".join(args)

    return f"{name} {arg_string}"

def make_option_string(name, attributes):
    out = []

    out.append(name)
    out.append(f" --{attributes.get('backend')}")

    if attributes.get("backend") == "http":
        out.append("--port")
        out.append(str(attributes.get('port')))

    if attributes["remove_prefix"]:
        out.append("--remove-prefix")

    return " ".join(out)

class UberspaceWebBackend(Item):
    """
    Manage uberspace web backends
    """
    BUNDLE_ATTRIBUTE_NAME = "uberspace_web_backend"
    ITEM_ATTRIBUTES = {
        "backend": "apache",
        "port": None,
        "remove_prefix": None,
    }
    ITEM_TYPE_NAME = "uberspace_web_backend"

    def __repr__(self):
        return f"<UberspaceWebBackend {make_display_string(self.name, self.attributes)}>"

    def cdict(self):
        cdict = {}
        for option, value in self.attributes.items():
            if value is not None:
                cdict[option] = value
        return cdict

    def fix(self, status):
        self.node.run(f"uberspace web backend set {make_option_string(self.name, self.attributes)}", may_fail=True)

    def sdict(self):
        return get_backend_config(self.node, self.name)

    @classmethod
    def validate_attributes(cls, bundle, item_id, attributes):

        if attributes.get("backend") == "apache":
            if attributes.get("port") is not None:
                raise BundleError(_(
                    "do not set 'port' while using 'apache' for 'backend' on {item} in bundle '{bundle}'"
                ).format(
                    item=item_id,
                    bundle=bundle.name,
                ))

            if attributes.get("remove_prefix") is not None:
                raise BundleError(_(
                    "do not set 'port' while using 'apache' for 'backend' on {item} in bundle '{bundle}'"
                ).format(
                    item=item_id,
                    bundle=bundle.name,
                ))

        elif attributes.get("backend") == "http":
            if not isinstance(attributes.get("port"), int):
                raise BundleError(_(
                    "'port' required and needs to be numeric while using 'http' for 'backend' on {item} in bundle '{bundle}'"
                ).format(
                    item=item_id,
                    bundle=bundle.name,
                ))

            if attributes.get("remove_prefix") not in [True, False, None]:
                raise BundleError(_(
                    "expected boolean for 'remove_prefix' on {item} in bundle '{bundle}'"
                ).format(
                    item=item_id,
                    bundle=bundle.name,
                ))

        else:
            raise BundleError(_(
                "expected 'apache' or 'http' for 'backend' on {item} in bundle '{bundle}'"
            ).format(
                item=item_id,
                bundle=bundle.name,
            ))