_have lxc && {
  _lxd_complete()
  {
    _lxd_operations()
    {
      COMPREPLY=( $( compgen -W "$( lxc operation list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_names()
    {
      local state=$1
      local keys=$2
      local project
      project=$(lxc project list --format=csv | sed -n 's/^\([^(]\+\) (current),.*/\1/ p')
      project=${project:-"default"}

      local cmd="lxc list --format=csv --columns=ns --project $project"
      [ -n "$state" ] && cmd="$cmd | grep -E ',$state$'"

      COMPREPLY=( $( compgen -W \
        "$( eval $cmd | cut -d, -f1 ) $keys" -- "$cur" )
      )
    }

    _lxd_images()
    {
      COMPREPLY=( $( compgen -W "$( lxc image list --format=csv --columns=l )" -- "$cur" ) )
    }

    _lxd_remotes()
    {
      COMPREPLY=( $( compgen -W "$( lxc remote list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_profiles()
    {
      COMPREPLY=( $( compgen -W "$( lxc profile list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_projects()
    {
      COMPREPLY=( $( compgen -W "$( lxc project list --format=csv | sed 's/,.\+//; s/ (current)$//' )" -- "$cur" ) )
    }

    _lxd_networks()
    {
      COMPREPLY=( $( compgen -W "$( lxc network list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_restore_snapshots()
    {
      local name=$1

      local query="/1.0/instances/$name/snapshots"

      COMPREPLY=( $( compgen -W "$( lxc query "$query" | sed -n "s|^\s*\"$query/\([^\"]\+\)\",\?$|\1|p" )" -- "$cur" ) )
    }

    _lxd_storage_pools()
    {
      COMPREPLY=( $( compgen -W "$( lxc storage list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_storage_volumes()
    {
      COMPREPLY=( $( compgen -W "$( lxc storage volume list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_auth_groups()
    {
      COMPREPLY=( $( compgen -W "$( lxc auth group list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_idp_groups()
    {
      COMPREPLY=( $( compgen -W "$( lxc auth identity-provider-group list --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    _lxd_warnings()
    {
      COMPREPLY=( $( compgen -W "$( lxc warning list --all --format=csv | cut -d, -f1 )" -- "$cur" ) )
    }

    COMPREPLY=()
    # ignore special --foo args
    if [[ ${COMP_WORDS[COMP_CWORD]} == -* ]]; then
      return 0
    fi

    if [ -n "${SNAP_COMMON:-""}" ]; then
      export LXD_DIR=${LXD_DIR:-"${SNAP_COMMON}/lxd/"}
    fi

    lxc_cmds="alias auth cluster config console copy delete exec export file \
      help image import info init launch list monitor move network \
      operation pause profile project publish query rebuild remote rename \
      restart restore shell snapshot start stop storage version warning"

    global_keys="acme.agree_tos acme.ca_url acme.domain acme.email \
      backups.compression_algorithm \
      core.bgp_address core.bgp_asn core.bgp_routerid \
      core.debug_address \
      core.dns_address \
      core.https_address \
      core.https_allowed_credential core.https_allowed_headers core.https_allowed_methods core.https_allowed_origin \
      core.https_trusted_proxy \
      core.metrics_address core.metrics_authentication \
      core.proxy_http core.proxy_https core.proxy_ignore_hosts \
      core.remote_token_expiry \
      core.shutdown_timeout \
      core.storage_buckets_address \
      core.syslog_socket \
      core.trust_ca_certificates \
      cluster.healing_threshold cluster.https_address cluster.images_minimal_replica cluster.join_token_expiry cluster.max_standby cluster.max_voters cluster.offline_threshold \
      images.auto_update_cached images.auto_update_interval \
      images.compression_algorithm images.default_architecture images.remote_cache_expiry \
      instances.migration.stateful instances.nic.host_name instances.placement.scriptlet \
      loki.api.ca_cert loki.api.url loki.auth.password loki.auth.username loki.instance loki.labels loki.loglevel loki.types \
      maas.api.key maas.api.url maas.machine \
      network.ovn.ca_cert network.ovn.client_cert network.ovn.client_key network.ovn.integration_bridge network.ovn.northbound_connection \
      oidc.audience oidc.client.id oidc.groups.claim oidc.issuer \
      storage.backups_volume storage.images_volume"

    instance_keys="agent.nic_config \
      boot.autostart boot.autostart.delay boot.autostart.priority \
      boot.debug_edk2 \
      boot.host_shutdown_timeout \
      boot.stop.priority \
      cloud-init.network-config cloud-init.user-data cloud-init.vendor-data \
      cluster.evacutate \
      environment. \
      limits.cpu limits.cpu.allowance limits.cpu.priority \
      limits.disk.priority \
      limits.hugepages.1GB limits.hugepages.1MB limits.hugepages.2MB limits.hugepages.64KB \
      limits.memory limits.memory.enforce \
      limits.memory.hugepages
      limits.memory.swap limits.memory.swap.priority \
      limits.processes \
      limits.kernel. \
      linux.kernel_modules \
      linux.kernel_modules.load \
      linux.sysctl. \
      migration.incremental.memory migration.incremental.memory.goal migration.incremental.memory.iterations migration.stateful \
      nvidia.driver.capabilities nvidia.require.cuda nvidia.require.driver nvidia.runtime \
      raw.apparmor raw.idmap raw.qemu raw.qemu.conf raw.lxc raw.seccomp \
      security.agent.metrics \
      security.csm \
      security.devlxd security.devlxd.images \
      security.idmap.base security.idmap.isolated security.idmap.size \
      security.nesting security.privileged \
      security.protection.delete security.protection.shift \
      security.secureboot \
      security.sev security.sev.es security.sev.policy.es security.sev.session.dh security.sev.session.data \
      security.syscalls.allow \
      security.syscalls.deny \
      security.syscalls.deny_compat security.syscalls.deny_default \
      security.syscalls.intercept.bpf security.syscalls.intercept.bpf.devices \
      security.syscalls.intercept.mknod \
      security.syscalls.intercept.mount security.syscalls.intercept.mount.allowed security.syscalls.intercept.mount.fuse security.syscalls.intercept.mount.shift \
      security.syscalls.intercept.sched_setscheduler \
      security.syscalls.intercept.setxattr \
      security.syscalls.intercept.sysinfo \
      snapshots.expiry snapshots.pattern snapshots.schedule snapshots.schedule.stopped \
      user. \
      volatile.apply_nvram \
      volatile.apply_template \
      volatile.base_image \
      volatile.cloud_init.instance-id \
      volatile.evacuate.origin \
      volatile.idmap.base volatile.idmap.current volatile.idmap.next \
      volatile.last_state.idmap volatile.last_state.power \
      volatile.uuid volatile.uuid.generation \
      volatile.vsock_id"

    device_keys="limits.ingress limits.egress ipv4.routes \
      ipv4.routes.external ipv6.routes ipv6.routes.external parent \
      name mtu hwaddr vlan maas.subnet.ipv4 maas.subnet.ipv6 nictype \
      host_name limits.max \
      ipv4.address ipv6.address ipv4.host_address ipv6.host_address ipv4.gateway ipv6.gateway \
      security.mac_filtering security.ipv4_filtering security.ipv6_filtering vlan limits.read \
      limits.write path source optional readonly size recursive pool \
      propagation shift major minor uid gid mode required vendorid productid \
      pci id listen connect bind nat proxy_protocol security.uid security.gid \
      boot.priority"

    networks_keys="bgp.ipv4.nexthop bgp.ipv6.nexthop bridge.driver bridge.external_interfaces bridge.mode \
      bridge.mtu bridge.hwaddr dns.domain dns.mode dns.search fan.overlay_subnet fan.type \
      fan.underlay_subnet ipv4.address ipv4.dhcp ipv4.dhcp.expiry ipv4.dhcp.gateway \
      ipv4.dhcp.ranges ipv4.firewall ipv4.nat ipv4.nat.address ipv4.nat.order ipv4.ovn.ranges \
      ipv4.routes ipv4.routing ipv6.address ipv6.dhcp ipv6.dhcp.expiry ipv6.dhcp.ranges \
      ipv6.dhcp.stateful ipv6.firewall ipv6.nat ipv6.nat.address ipv6.nat.order ipv6.ovn.ranges \
      ipv6.routes ipv6.routing maas.subnet.ipv4 maas.subnet.ipv6 mtu network parent raw.dnsmasq vlan"

    project_keys="features.images features.profiles features.storage.volumes \
      limits.containers limits.virtual-machines limits.memory limits.processes limits.cpu \
      restricted restricted.containers.nesting restricted.containers.interception restricted.containers.lowlevel \
      restricted.containers.privilege restricted.virtual-machines.lowlevel restricted.devices.unix-char \
      restricted.devices.unix-block restricted.devices.unix-hotplug restricted.devices.infiniband \
      restricted.devices.gpu restricted.devices.usb restricted.devices.nic restricted.devices.disk \
      restricted.devices.pci restricted.devices.proxy"

    storage_pool_keys="source size btrfs.mount_options ceph.cluster_name \
      ceph.osd.pg_num ceph.osd.pool_name ceph.osd.data_pool_name \
      ceph.rbd.clone_copy ceph.rbd.du ceph.rbd.features ceph.user.name cephfs.cluster_name cephfs.path \
      cephfs.fscache cephfs.vg_name lvm.thinpool_name lvm.thinpool_metadata_size lvm.use_thinpool \
      lvm.vg_name rsync.bwlimit volatile.initial_source \
      volatile.pool.pristine volume.block.filesystem \
      volume.block.mount_options volume.size volume.zfs.remove_snapshots volume.zfs.delegate \
      volume.zfs.use_refquota zfs.clone_copy zfs.pool_name volume.zfs.reserve_space"

    storage_volume_keys="size block.filesystem block.mount_options \
      security.unmapped security.shifted zfs.remove_snapshots zfs.use_refquota zfs.reserve_space
      zfs.delegate"

    auth_entity_types="server group image instance network profile project storage storage_volume"

    if [ "$COMP_CWORD" -eq 1 ]; then
      COMPREPLY=( $(compgen -W "$lxc_cmds" -- ${COMP_WORDS[COMP_CWORD]}) )
      return 0
    fi

    local no_dashargs
    cur=${COMP_WORDS[COMP_CWORD]}

    no_dashargs=(${COMP_WORDS[@]// -*})
    pos=$((COMP_CWORD - (${#COMP_WORDS[@]} - ${#no_dashargs[@]})))
    if [ -z "$cur" ]; then
      pos=$((pos + 1))
    fi

    case ${no_dashargs[1]} in
      "alias")
        COMPREPLY=( $(compgen -W "add list remove rename" -- "$cur") )
        ;;
      "auth")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "group identity identity-provider-group idp-group permission" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "group")
                COMPREPLY=( $(compgen -W "create delete edit list permission rename show" -- "$cur") )
                ;;
              "identity"|"user")
                COMPREPLY=( $(compgen -W "edit group info list show" -- "$cur") )
                ;;
              "identity-provider-group"|"idp-group")
                COMPREPLY=( $(compgen -W "create delete edit group list rename show" -- "$cur") )
                ;;
              "permission"|"perm")
                COMPREPLY=( $(compgen -W "list" -- "$cur") )
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "group")
                case ${no_dashargs[3]} in
                  "permission"|"perm")
                    COMPREPLY=( $(compgen -W "add remove" -- "$cur") )
                    ;;
                  "delete"|"edit"|"rename"|"show")
                    _lxd_auth_groups
                    ;;
                esac
                ;;
              "identity"|"user")
                case ${no_dashargs[3]} in
                  "group")
                    COMPREPLY=( $(compgen -W "add remove" -- "$cur" ) )
                    ;;
                esac
                ;;
              "identity-provider-group"|"idp-group")
                case ${no_dashargs[3]} in
                  "delete"|"edit"|"rename"|"show")
                    _lxd_idp_groups
                    ;;
                  "group")
                    COMPREPLY=( $(compgen -W "add remove" -- "$cur") )
                    ;;
                esac
                ;;
            esac
            ;;
          5)
            case ${no_dashargs[2]} in
              "group")
                case ${no_dashargs[3]} in
                  "permission"|"perm")
                    _lxd_auth_groups
                    ;;
                esac
                ;;
              "identity-provider-group"|"idp-group")
                case ${no_dashargs[3]} in
                  "group")
                    _lxd_idp_groups
                    ;;
                esac
                ;;
            esac
            ;;
          6)
            case ${no_dashargs[2]} in
              "group")
                case ${no_dashargs[3]} in
                  "permission"|"perm")
                    COMPREPLY=( $(compgen -W "$auth_entity_types" -- "$cur" ) )
                    ;;
                esac
                ;;
              "identity"|"user")
                case ${no_dashargs[3]} in
                  "group")
                    _lxd_auth_groups
                    ;;
                esac
                ;;
              "identity-provider-group"|"idp-group")
                case ${no_dashargs[3]} in
                  "group")
                    _lxd_auth_groups
                    ;;
                esac
                ;;
            esac
            ;;
        esac
        ;;
      "config")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "device edit get metadata set show template trust uefi unset" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "trust")
                COMPREPLY=( $(compgen -W "add edit list list-tokens remove revoke-token show" -- "$cur") )
                ;;
              "uefi")
                COMPREPLY=( $(compgen -W "edit get set show unset" -- "$cur") )
                ;;
              "device")
                COMPREPLY=( $(compgen -W "add get list override remove set show unset" -- "$cur") )
                ;;
              "metadata")
                COMPREPLY=( $(compgen -W "show edit" -- "$cur") )
                ;;
              "template")
                COMPREPLY=( $(compgen -W "create delete edit list show" -- "$cur") )
                ;;
              "show"|"edit")
                _lxd_names
                ;;
              "get"|"set"|"unset")
                _lxd_names "" "$global_keys"
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "trust")
                _lxd_remotes
                ;;
              "uefi")
                _lxd_names
                ;;
              "device")
                _lxd_names
                ;;
              "get"|"set"|"unset")
                COMPREPLY=( $(compgen -W "$instance_keys" -- "$cur") )
                ;;
            esac
            ;;
          6)
            case ${no_dashargs[2]} in
              "device")
                case ${no_dashargs[3]} in
                "get"|"set"|"unset")
                  COMPREPLY=( $(compgen -W "$device_keys" -- "$cur") )
                ;;
                esac
              ;;
            esac
            ;;
        esac
        ;;
      "copy")
        if [ $pos -lt 4 ]; then
          _lxd_names
        fi
        ;;
      "delete"|"info"|"move"|"publish"|"rename"|"restart"|"snapshot")
        _lxd_names
        ;;
      "start")
        _lxd_names "(STOPPED|FROZEN)"
        ;;
      "exec"|"console"|"pause"|"stop"|"shell")
        _lxd_names "(RUNNING|READY)"
        ;;
      "file")
        COMPREPLY=( $(compgen -W "pull push edit delete mount" -- "$cur") )
        ;;
      "help")
        COMPREPLY=( $(compgen -W "$lxc_cmds" -- "$cur") )
        ;;
      "image")
        COMPREPLY=( $(compgen -W "alias copy delete edit export get-property import info list refresh set-property show unset-property" -- "$cur") )
        ;;
      "init"|"launch"|"rebuild")
        _lxd_images
        ;;
      "network")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "acl attach attach-profile create delete detach detach-profile edit forward get info list list-allocations list-leases load-balancer peer rename set show unset zone" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "show"|"get"|"set"|"unset"|"delete"|"edit"|"rename"|"attach"|"attach-profile"|"detach"|"detach-profile"|"info"|"acl"|"forward"|"list-leases"|"load-balancer"|"peer"|"zone")
                _lxd_networks
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "get"|"set"|"unset")
                COMPREPLY=( $(compgen -W "$networks_keys" -- "$cur") )
                ;;
              "attach"|"detach"|"detach-profile")
                _lxd_names
                ;;
              "attach-profile")
                _lxd_profiles
                ;;
            esac
        esac
        ;;
      "operation")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "delete list show" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "delete"|"show")
                _lxd_operations
                ;;
            esac
            ;;
        esac
        ;;
      "profile")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "list show create copy get set unset delete edit rename assign add remove device " -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "device")
                COMPREPLY=( $(compgen -W "list show remove get set unset add" -- "$cur") )
                ;;
              "add"|"assign"|"remove")
                _lxd_names
                ;;
              *)
                _lxd_profiles
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "device"|"add"|"assign"|"remove")
                _lxd_profiles
                ;;
              *)
                COMPREPLY=( $(compgen -W "$instance_keys" -- "$cur") )
                ;;
            esac
            ;;
          6)
            case ${no_dashargs[2]} in
              "device")
                case ${no_dashargs[3]} in
                "get"|"set"|"unset")
                  COMPREPLY=( $(compgen -W "$device_keys" -- "$cur") )
                ;;
                esac
              ;;
            esac
            ;;
        esac
        ;;
      "project")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "create delete edit get list rename set show switch unset " -- "$cur") )
            ;;

          3)
            case ${no_dashargs[2]} in
              "get"|"set"|"unset"|"create"|"delete"|"edit"|"list"|"show"|"switch"|"rename")
                _lxd_projects
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "get"|"set"|"unset")
                COMPREPLY=( $(compgen -W "$project_keys" -- "$cur") )
                ;;
            esac
            ;;
          5)
            case ${no_dashargs[2]} in
              "rename")
                _lxd_projects
                ;;
            esac
            ;;
        esac
        ;;
      "remote")
        COMPREPLY=( $(compgen -W \
          "add get-default list remove rename set-url switch" -- "$cur") )
        ;;
      "restore")
        case $pos in
          2)
            _lxd_names
            ;;
          3)
            _lxd_restore_snapshots "${no_dashargs[2]}"
            ;;
        esac
        ;;
      "storage")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "bucket create delete edit get info list set show unset volume" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "delete"|"edit"|"get"|"info"|"set"|"show"|"unset")
                _lxd_storage_pools
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "get"|"set"|"unset")
                COMPREPLY=( $(compgen -W "$storage_pool_keys" -- "$cur") )
                ;;
            esac
            ;;
        esac
        ;;
      "storage_volumes")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "list show create rename get set unset delete edit attach attach-profile detach detach-profile" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "show"|"get"|"set"|"unset"|"rename"|"delete"|"edit"|"attach"|"attach-profile"|"detach"|"detach-profile")
                _lxd_storage_volumes
                ;;
            esac
            ;;
          4)
            case ${no_dashargs[2]} in
              "get"|"set"|"unset")
                COMPREPLY=( $(compgen -W "$storage_volume_keys" -- "$cur") )
                ;;
              "attach"|"detach"|"detach-profile")
                _lxd_names
                ;;
              "attach-profile")
                _lxd_profiles
                ;;
            esac
            ;;
        esac
        ;;
      "warning")
        case $pos in
          2)
            COMPREPLY=( $(compgen -W "acknowledge delete list show" -- "$cur") )
            ;;
          3)
            case ${no_dashargs[2]} in
              "acknowledge"|"delete"|"show")
                _lxd_warnings
                ;;
            esac
            ;;
        esac
        ;;
      *)
        ;;
    esac

    return 0
  }

  complete -o default -F _lxd_complete lxc lxd.lxc
}
