"""ORCH-101 (TC-09, AC-5 / NFR-3): scripts/gen_secrets.py — выпуск нового
комплекта секретов.

Контракт D8: криптослучайные webhook-секреты (>= 32 байт энтропии, hex);
повторный запуск даёт другие значения; существующий .env никогда не
перезаписывается молча (отказ exit=2, перезапись только --force); состав
ключей вывода согласован с .env.example.
"""

import importlib.util
import re
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[1]
SCRIPT = REPO_ROOT / "scripts/gen_secrets.py"
ENV_EXAMPLE = REPO_ROOT / ".env.example"

_HEX64 = re.compile(r"^[0-9a-f]{64}$")


def _load_module():
    spec = importlib.util.spec_from_file_location("gen_secrets", SCRIPT)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


def _values(fragment: str) -> dict[str, str]:
    out = {}
    for line in fragment.splitlines():
        if "=" in line and not line.startswith("#"):
            k, v = line.split("=", 1)
            out[k] = v
    return out


def test_secret_is_cryptorandom_64_hex():
    mod = _load_module()
    assert mod.TOKEN_BYTES >= 32  # AC-5: >= 32 байта энтропии
    value = mod.generate_secret()
    assert _HEX64.match(value), value


def test_two_runs_give_different_values():
    mod = _load_module()
    a, b = _values(mod.build_fragment()), _values(mod.build_fragment())
    for key in mod.GENERATED_KEYS:
        assert _HEX64.match(a[key]) and _HEX64.match(b[key])
        assert a[key] != b[key], f"{key}: повторный запуск дал то же значение"


def test_external_tokens_are_placeholders():
    mod = _load_module()
    vals = _values(mod.build_fragment())
    for key in mod.EXTERNAL_KEYS:
        assert vals[key] == "", f"{key} должен быть пустым плейсхолдером"


def test_output_keys_consistent_with_env_example():
    """AC-5: каждое имя ключа из вывода генератора существует в .env.example."""
    mod = _load_module()
    example = ENV_EXAMPLE.read_text(encoding="utf-8")
    example_keys = {
        line.split("=", 1)[0].strip()
        for line in example.splitlines()
        if "=" in line and not line.strip().startswith("#")
    }
    for key in (*mod.GENERATED_KEYS, *mod.EXTERNAL_KEYS):
        assert key in example_keys, f"{key} отсутствует в .env.example"


def test_default_mode_prints_and_touches_no_files(tmp_path, capsys, monkeypatch):
    mod = _load_module()
    monkeypatch.chdir(tmp_path)
    rc = mod.main([])
    assert rc == 0
    out = capsys.readouterr().out
    assert "ORCH_PLANE_WEBHOOK_SECRET=" in out
    assert list(tmp_path.iterdir()) == []  # filesystem untouched


def test_write_refuses_existing_file_without_force(tmp_path):
    mod = _load_module()
    target = tmp_path / ".env"
    target.write_text("KEEP=1\n", encoding="utf-8")
    rc = mod.main(["--write", str(target)])
    assert rc == 2  # отказ, не перезапись
    assert target.read_text(encoding="utf-8") == "KEEP=1\n"  # содержимое цело


def test_write_creates_new_file_and_force_overwrites(tmp_path):
    mod = _load_module()
    target = tmp_path / ".env"
    assert mod.main(["--write", str(target)]) == 0
    first = _values(target.read_text(encoding="utf-8"))
    assert _HEX64.match(first["ORCH_GITEA_WEBHOOK_SECRET"])
    # --force перезаписывает, и секреты другие (не детерминированы).
    assert mod.main(["--write", str(target), "--force"]) == 0
    second = _values(target.read_text(encoding="utf-8"))
    assert first["ORCH_GITEA_WEBHOOK_SECRET"] != second["ORCH_GITEA_WEBHOOK_SECRET"]


def test_no_real_secret_committed_anywhere_near():
    """Генератор не несёт зашитых значений: единственный источник — CSPRNG."""
    text = SCRIPT.read_text(encoding="utf-8")
    assert not re.search(r"[0-9a-f]{32,}", text), "зашитое hex-значение в генераторе"
