#!/usr/bin/env python3
"""Attrappe von `pvesh` - beantwortet Abfragen aus demo/state.json.

Nur so viel, wie die Oberflaechen fuer die Bildschirmfotos brauchen. Alles,
was etwas veraendern wuerde, gibt brav eine UPID zurueck und tut nichts.
"""

import json
import os
import sys

STATE = os.environ.get("PVESNAP_DEMO_STATE", "")


def load():
    with open(STATE, "r", encoding="utf-8") as handle:
        return json.load(handle)


def main(argv):
    if len(argv) < 2:
        return 1
    verb, path = argv[0], argv[1]
    args = {}
    rest = argv[2:]
    index = 0
    while index < len(rest):
        if rest[index].startswith("--"):
            key = rest[index][2:]
            value = rest[index + 1] if index + 1 < len(rest) else ""
            args[key] = value
            index += 2
        else:
            index += 1

    data = load()
    parts = [p for p in path.strip("/").split("/") if p]

    if verb == "get":
        result = handle_get(parts, args, data)
        if result is _MISS:
            print("no such resource '%s'" % path, file=sys.stderr)
            return 2
        if args.get("output-format") == "json":
            print(json.dumps(result))
        else:
            print(result)
        return 0

    # Alles Veraendernde: Proxmox liefert eine UPID, der Aufrufer wartet darauf.
    node = parts[1] if len(parts) > 1 and parts[0] == "nodes" else "pve1"
    if parts[-1] == "spiceproxy":
        print(json.dumps({
            "type": "spice", "host": "pvespiceproxy:63f4a2b1:100:pve1::abc",
            "proxy": "http://10.20.0.11", "tls-port": 61000,
            "password": "aG9jaGdlaGVpbQ==", "ca": "-----BEGIN CERTIFICATE-----\\n"
            "MIIFxTCCA62gAwIBAgIB...\\n-----END CERTIFICATE-----\\n",
            "host-subject": "OU=PVE Cluster Node,O=Proxmox Virtual Environment,"
                            "CN=pve1.hausnetz.lan",
            "delete-this-file": 1, "secure-attention": "Ctrl+Alt+Ins",
            "toggle-fullscreen": "Shift+F11", "release-cursor": "Ctrl+Alt+R",
            "title": "VM 9102 - warenwirtschaft-w",
        }))
        return 0
    print("UPID:%s:00001A2B:0BC3D4E5:68970000:qmsnapshot:100:root@pam:" % node)
    return 0


_MISS = object()


def handle_get(parts, args, data):
    if parts == ["cluster", "resources"]:
        return data["resources"]
    if len(parts) == 2 and parts[0] == "storage":
        return {"ceph-vm": {"type": "rbd", "pool": "vmdaten", "shared": 1,
                            "content": "images", "storage": "ceph-vm",
                            "krbd": 0, "monhost": "10.20.0.11 10.20.0.12"},
                "ceph-ct": {"type": "rbd", "pool": "ctdaten", "shared": 1,
                            "content": "rootdir", "storage": "ceph-ct"},
                "local": {"type": "dir", "shared": 0, "storage": "local",
                          "content": "iso,vztmpl,backup"},
                }.get(parts[1], _MISS)
    if parts == ["storage"]:
        # Die Liste traegt dieselben Felder wie der Einzelabruf - besonders
        # "pool". Ohne das wuerde jeder rbd-Aufruf im Standard-Pool landen.
        return [{"storage": "ceph-vm", "type": "rbd", "shared": 1,
                 "pool": "vmdaten", "content": "images",
                 "monhost": "10.20.0.11 10.20.0.12"},
                {"storage": "ceph-ct", "type": "rbd", "shared": 1,
                 "pool": "ctdaten", "content": "rootdir"},
                {"storage": "local", "type": "dir", "shared": 0,
                 "content": "iso,vztmpl,backup"}]
    if parts == ["cluster", "nextid"]:
        wanted = args.get("vmid")
        if wanted:
            taken = {str(r["vmid"]) for r in data["resources"]}
            if str(wanted) in taken:
                print("VM %s already exists" % wanted, file=sys.stderr)
                sys.exit(2)
            return int(wanted)
        return data["nextid"]

    # Muss vor dem allgemeinen /nodes-Zweig stehen: sonst wird "tasks" fuer
    # eine Gastart gehalten und /status liefert einen leeren Datensatz - die
    # Warteschleife auf den Task laeuft dann bis zum Zeitlimit.
    if len(parts) >= 3 and parts[0] == "nodes" and parts[2] == "tasks":
        if parts[-1] == "log":
            return [{"n": 1, "t": "TASK OK"}]
        return {"status": "stopped", "exitstatus": "OK", "type": "qmconfig",
                "upid": parts[3] if len(parts) > 3 else "", "node": parts[1]}

    if len(parts) >= 4 and parts[0] == "nodes":
        node, kind, vmid = parts[1], parts[2], parts[3]
        key = "%s/%s/%s" % (node, kind, vmid)
        tail = parts[4:]

        if tail == ["snapshot"]:
            entries = list(data["snapshots"].get(key, []))
            entries.append({"name": "current", "digest": "0" * 40,
                            "description": "You are here!",
                            "parent": entries[-1]["name"] if entries else ""})
            return entries
        if tail == ["config"]:
            return _conf(data["configs"].get(key, ""))
        if len(tail) == 3 and tail[0] == "snapshot" and tail[2] == "config":
            base = _conf(data["configs"].get(key, ""))
            base["parent"] = tail[1]
            base["snaptime"] = next(
                (s["snaptime"] for s in data["snapshots"].get(key, [])
                 if s["name"] == tail[1]), 0)
            # Ein Snapshot "mit RAM" traegt den Arbeitsspeicher als eigenes
            # Volume; genau daran erkennt pvesnap, dass es warm gehen kann.
            if tail[1].startswith("auto-stuendlich"):
                base["vmstate"] = "ceph-vm:vm-%s-state-%s" % (vmid, tail[1])
                base["runningmachine"] = "pc-i440fx-9.0+pve0"
                base["runningcpu"] = "x86-64-v2-AES,enforce"
            return base
        if tail == ["status", "current"]:
            return data["status"].get(key, {})
        if tail and tail[0] == "status":
            return data["status"].get(key, {})

    return _MISS


def _conf(text):
    result = {}
    for line in text.splitlines():
        if ":" in line and not line.startswith("#"):
            key, _, value = line.partition(":")
            result[key.strip()] = value.strip()
    for key in ("cores", "memory", "sockets", "numa", "agent"):
        if key in result:
            try:
                result[key] = int(result[key])
            except ValueError:
                pass
    return result


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
