import json


class IncusHost(QemuMachine):
    def __init__(self, base):
        with subtest("Wait for startup"):
            base.wait_for_unit("incus.service")
            base.wait_for_unit("incus-preseed.service")

        with subtest("Verify preseed resources created"):
            base.succeed("incus profile show default")
            base.succeed("incus network info incusbr0")
            base.succeed("incus storage show default")

        self._parent = base

    # delegate attribute access to the parent
    def __getattr__(self, name):
        return getattr(self._parent, name)

    def instance_exec(self, name: str, command: str, project: str = "default"):
        return super().execute(
            f"incus exec {name} --disable-stdin --force-interactive --project {project} -- {command}"
        )

    def instance_succeed(self, name: str, command: str, project: str = "default"):
        return super().succeed(
            f"incus exec {name} --disable-stdin --force-interactive --project {project} -- {command}"
        )

    def wait_for_instance(self, name: str, project: str = "default"):
        self.wait_instance_exec_success(
            name,
            "/run/current-system/sw/bin/systemctl is-system-running",
            project=project,
        )

    def wait_instance_exec_success(
        self, name: str, command: str, timeout: int = 900, project: str = "default"
    ):
        def check_command(_) -> bool:
            status, _ = self.instance_exec(name, command, project)
            return status == 0

        with super().nested(
            f"Waiting for successful instance exec, instance={name}, project={project}, command={command}"
        ):
            retry(check_command, timeout)

    def set_instance_config(
        self, name: str, config: str, restart: bool = False, unset: bool = False
    ):
        if restart:
            super().succeed(f"incus stop {name}")

        if unset:
            super().succeed(f"incus config unset {name} {config}")
        else:
            super().succeed(f"incus config set {name} {config}")

        if restart:
            super().succeed(f"incus start {name}")
            self.wait_for_instance(name)
        else:
            # give a moment to settle
            super().sleep(1)

    def cleanup(self):
        # avoid conflict between preseed and cleanup operations
        super().execute("systemctl kill incus-preseed.service")

        instances = json.loads(
            super().succeed("incus list --format json --all-projects")
        )
        for instance in [a for a in instances if a["status"] == "Running"]:
            super().execute(
                f"incus stop --force {instance['name']} --project {instance['project']}"
            )
            super().execute(
                f"incus delete --force {instance['name']} --project {instance['project']}"
            )

    def check_instance_sysctl(self, name: str, project: str = "default"):
        self.instance_succeed(name, "systemctl status systemd-sysctl", project)
        sysctl = (
            self.instance_succeed(name, "sysctl net.ipv4.ip_forward", project)
            .strip()
            .split(" ")[-1]
        )
        assert "1" == sysctl, (
            f"systemd-sysctl configuration not correctly applied, {sysctl} != 1"
        )
