"""子进程 / Host IPC 使用的一次性 nonce（plugins/.state/host_nonces/）。"""

from __future__ import annotations

import secrets
import time
from pathlib import Path


def issue_host_nonce(state_dir: Path, *, ttl_sec: int = 3600) -> str:
    """写入 ``<state_dir>/host_nonces/<id>``，返回 ``id:secret`` 供子进程环境变量或 JSON auth。"""

    root = (state_dir / "host_nonces").resolve()
    root.mkdir(parents=True, exist_ok=True)
    nonce_id = secrets.token_hex(8)
    secret = secrets.token_hex(16)
    expire = int(time.time()) + max(60, int(ttl_sec))
    (root / nonce_id).write_text(
        f"{secret}\n{expire}\n",
        encoding="utf-8",
        newline="\n",
    )
    return f"{nonce_id}:{secret}"


def verify_host_nonce(state_dir: Path, token: str | None) -> tuple[bool, str]:
    """校验 ``id:secret``；格式不对视为跳过（兼容未使用 nonce 的启动）。"""

    if not token or ":" not in token:
        return True, "no_nonce"
    nid, _, sec = token.partition(":")
    nid, sec = nid.strip(), sec.strip()
    if not nid or not sec:
        return False, "invalid_nonce_format"
    path = (Path(state_dir) / "host_nonces" / nid).resolve()
    root = (Path(state_dir) / "host_nonces").resolve()
    try:
        path.relative_to(root)
    except ValueError:
        return False, "invalid_nonce_path"
    if not path.is_file():
        return False, "nonce_not_found"
    try:
        lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
        file_secret = (lines[0] if lines else "").strip()
        exp_raw = (lines[1] if len(lines) > 1 else "0").strip()
        expire = int(exp_raw) if exp_raw.isdigit() else 0
    except (OSError, ValueError):
        return False, "nonce_read_failed"
    if secrets.compare_digest(file_secret, sec) is False:
        return False, "nonce_secret_mismatch"
    if int(time.time()) > expire:
        return False, "nonce_expired"
    return True, "ok"
