#!/usr/bin/env python3
"""
ozone-wadmin-prod — Ozone/verification-labeler operations against prod.

Reads Ozone secrets from the prod k8s 'pds' secret, opens a kubectl
port-forward to the prod PDS pod (so createSession is reachable without
going through the public nginx), then delegates to the ozone CLI.
The port-forward is killed automatically when the script exits.

Usage:
    ./ozone-wadmin-prod --help
    ./ozone-wadmin-prod verification verify <did> --account-type personal [options]
    ./ozone-wadmin-prod verification revoke <did>

Requires:
    kubectl + ~/.wsocial/kube/prod.yaml
    The 'pds' k8s secret must contain:
        OZONE_HOST, OZONE_ADMIN_PASSWORD, OZONE_LABELER_DID, OZONE_LABELER_PASSWORD
"""

import atexit
import base64
import json
import os
import socket
import subprocess
import sys
import time
from pathlib import Path

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

SCRIPT_DIR = Path(__file__).parent.resolve()
VENV_PYTHON = SCRIPT_DIR / "pds-wadmin-modules" / ".venv" / "bin" / "python3"

KUBECONFIG_PROD = Path.home() / ".wsocial" / "kube" / "prod.yaml"
K8S_NAMESPACE = "pds"
K8S_POD = "pds-0"
PDS_CONTAINER_PORT = 3000
LOCAL_FORWARD_PORT = 12583
K8S_OZONE_NAMESPACE = "ozone"
K8S_OZONE_SECRET = "ozone"


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _check_venv():
    if not VENV_PYTHON.exists():
        print(f"ERROR: venv not found at {VENV_PYTHON}", file=sys.stderr)
        print(
            "Run: cd pds-wadmin-modules && python3 -m venv .venv && "
            ".venv/bin/pip install -e .",
            file=sys.stderr,
        )
        sys.exit(1)


def _read_k8s_secrets() -> dict:
    """Read and base64-decode all entries from the 'ozone' k8s secret."""
    print("Reading secrets from k8s ozone secret…", file=sys.stderr)
    env = {**os.environ, "KUBECONFIG": str(KUBECONFIG_PROD)}
    try:
        result = subprocess.run(
            ["kubectl", "get", "secret", K8S_OZONE_SECRET,
             "-n", K8S_OZONE_NAMESPACE, "-o", "jsonpath={.data}"],
            capture_output=True, text=True, check=True, env=env,
        )
    except FileNotFoundError:
        print(
            "ERROR: kubectl not found — install kubectl and ensure it is on your PATH",
            file=sys.stderr,
        )
        sys.exit(1)
    except subprocess.CalledProcessError as exc:
        print(
            f"ERROR: could not read '{K8S_OZONE_SECRET}' secret from ozone namespace:\n  {exc.stderr.strip()}",
            file=sys.stderr,
        )
        sys.exit(1)

    raw = json.loads(result.stdout)
    return {k: base64.b64decode(v).decode() for k, v in raw.items()}


def _start_port_forward(env: dict) -> subprocess.Popen:
    print(
        f"Starting port-forward to {K8S_POD}:{PDS_CONTAINER_PORT}"
        f" → localhost:{LOCAL_FORWARD_PORT}…",
        file=sys.stderr,
    )
    return subprocess.Popen(
        ["kubectl", "port-forward",
         "-n", K8S_NAMESPACE, f"pod/{K8S_POD}",
         f"{LOCAL_FORWARD_PORT}:{PDS_CONTAINER_PORT}"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
        env=env,
    )


def _wait_for_port(port: int, timeout: float = 10.0):
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        try:
            with socket.create_connection(("127.0.0.1", port), timeout=0.5):
                return
        except OSError:
            time.sleep(0.25)
    print("ERROR: port-forward did not become ready in time", file=sys.stderr)
    sys.exit(1)


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def main():
    args = sys.argv[1:]

    _check_venv()

    # Pass --help / -h (at any position) and bare invocation straight through
    # to the CLI — no k8s setup needed just to print usage.
    if not args or "--help" in args or "-h" in args:
        os.execve(
            str(VENV_PYTHON),
            [str(VENV_PYTHON), "-m", "wadmin.ozone_cli"] + args,
            os.environ,
        )
        return  # unreachable

    if not KUBECONFIG_PROD.exists():
        print(f"ERROR: kubeconfig not found: {KUBECONFIG_PROD}", file=sys.stderr)
        sys.exit(1)

    secrets = _read_k8s_secrets()

    # The ozone k8s secret uses slightly different key names — map them.
    # OZONE_LABELER_PASSWORD must be added manually to the ozone secret.
    required_keys = [
        "OZONE_ADMIN_PASSWORD",   # same key name in ozone secret
        "OZONE_PUBLIC_URL",       # → OZONE_HOST
        "OZONE_SERVER_DID",       # → OZONE_LABELER_DID
        "OZONE_LABELER_PASSWORD", # custom key, must be added to ozone secret
    ]
    missing = [k for k in required_keys if not secrets.get(k)]
    if missing:
        print(
            f"ERROR: missing keys in ozone k8s secret '{K8S_OZONE_SECRET}': {', '.join(missing)}",
            file=sys.stderr,
        )
        sys.exit(1)

    env = os.environ.copy()
    env["OZONE_HOST"] = secrets["OZONE_PUBLIC_URL"]
    env["OZONE_ADMIN_PASSWORD"] = secrets["OZONE_ADMIN_PASSWORD"]
    env["OZONE_LABELER_DID"] = secrets["OZONE_SERVER_DID"]
    env["OZONE_LABELER_PASSWORD"] = secrets["OZONE_LABELER_PASSWORD"]
    env["OZONE_LABELER_PDS_HOST"] = f"http://localhost:{LOCAL_FORWARD_PORT}"

    forward_proc = _start_port_forward({**env, "KUBECONFIG": str(KUBECONFIG_PROD)})

    def _cleanup():
        forward_proc.terminate()
        try:
            forward_proc.wait(timeout=3)
        except subprocess.TimeoutExpired:
            forward_proc.kill()

    atexit.register(_cleanup)

    _wait_for_port(LOCAL_FORWARD_PORT)

    ret = subprocess.call(
        [str(VENV_PYTHON), "-m", "wadmin.ozone_cli"] + args,
        env=env,
    )
    sys.exit(ret)


if __name__ == "__main__":
    main()
