"""tests/regression/test_automation_audit_helpers.py — task-2471+1 자동화 회귀.

회장 명령 (E): regression test 5건 — 자동화 헬퍼 함수 (audit jsonl 보존,
sha256 chunked, slugify) 의 회귀 차단.

검증 대상:
- ``_sha256_file`` chunked 처리 (대용량 OOM-safe)
- ``_append_audit_jsonl`` parent dir 자동 생성 + 한 줄당 한 record
- ``_slugify_reason`` archive path suffix 안전 변환
- ``ESCALATED_AUDIT_LOG`` / ``BRANCH_CLEANUP_LOG`` /
  ``CONSISTENCY_AUDIT_LOG`` 경로 상수 검증
"""
from __future__ import annotations

import hashlib
import importlib.util
import json
import sys
from pathlib import Path

import pytest

WORKSPACE = Path(__file__).resolve().parents[2]


def _load_taskctl(monkeypatch: pytest.MonkeyPatch, root: Path):
    monkeypatch.setenv("WORKSPACE_ROOT", str(root))
    spec = importlib.util.spec_from_file_location(
        "taskctl_helpers_isolated",
        str(WORKSPACE / "scripts" / "taskctl.py"),
    )
    assert spec and spec.loader
    mod = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = mod
    spec.loader.exec_module(mod)
    return mod


@pytest.fixture()
def mod(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
    return _load_taskctl(monkeypatch, tmp_path)


def test_sha256_file_matches_hashlib_for_small(mod, tmp_path: Path) -> None:
    p = tmp_path / "small.bin"
    data = b"hello world\n" * 10
    p.write_bytes(data)
    expected = hashlib.sha256(data).hexdigest()
    assert mod._sha256_file(p) == expected


def test_sha256_file_chunked_for_large(mod, tmp_path: Path) -> None:
    p = tmp_path / "large.bin"
    data = b"a" * (65536 * 3 + 17)  # 3 chunks + remainder
    p.write_bytes(data)
    expected = hashlib.sha256(data).hexdigest()
    assert mod._sha256_file(p) == expected


def test_sha256_empty_file(mod, tmp_path: Path) -> None:
    p = tmp_path / "empty.bin"
    p.touch()
    assert (
        mod._sha256_file(p)
        == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    )


def test_append_audit_jsonl_creates_parent_dir(mod, tmp_path: Path) -> None:
    log = tmp_path / "deeply" / "nested" / "audit.jsonl"
    assert not log.parent.exists()
    mod._append_audit_jsonl(log, {"k": 1})
    assert log.exists()
    line = log.read_text(encoding="utf-8")
    assert json.loads(line.strip())["k"] == 1


def test_append_audit_jsonl_appends_records(mod, tmp_path: Path) -> None:
    log = tmp_path / "audit.jsonl"
    for i in range(5):
        mod._append_audit_jsonl(log, {"i": i, "msg": f"r{i}"})
    lines = [
        l for l in log.read_text(encoding="utf-8").splitlines() if l.strip()
    ]
    assert len(lines) == 5
    parsed = [json.loads(l) for l in lines]
    assert [r["i"] for r in parsed] == list(range(5))


def test_append_audit_jsonl_unicode_safe(mod, tmp_path: Path) -> None:
    log = tmp_path / "audit_unicode.jsonl"
    record = {"reason": "한글 테스트 ✅", "task_id": "task-test"}
    mod._append_audit_jsonl(log, record)
    text = log.read_text(encoding="utf-8")
    parsed = json.loads(text.strip())
    assert parsed["reason"] == "한글 테스트 ✅"


def test_slugify_reason_strips_unsafe_chars(mod) -> None:
    assert mod._slugify_reason("stale 30min!!!") == "stale-30min"
    assert mod._slugify_reason("/path/with/slash") == "path-with-slash"
    assert mod._slugify_reason("") == "archived"
    assert mod._slugify_reason("!!!") == "archived"


def test_slugify_reason_max_len(mod) -> None:
    long_reason = "a" * 200
    out = mod._slugify_reason(long_reason)
    assert len(out) <= 40


def test_audit_log_constants_under_orchestration_audit(mod) -> None:
    """3 audit jsonl 경로 모두 ``orchestration-audit/`` 하위에 위치 (정책)."""
    for const_name in (
        "ESCALATED_AUDIT_LOG",
        "BRANCH_CLEANUP_LOG",
        "CONSISTENCY_AUDIT_LOG",
    ):
        path = getattr(mod, const_name)
        assert path.parent.name == "orchestration-audit", (
            f"{const_name} not under orchestration-audit/: {path}"
        )
        assert path.suffix == ".jsonl"


def test_audit_log_constants_distinct(mod) -> None:
    """3 audit log은 서로 다른 파일 (mixing 방지)."""
    paths = {
        mod.ESCALATED_AUDIT_LOG,
        mod.BRANCH_CLEANUP_LOG,
        mod.CONSISTENCY_AUDIT_LOG,
    }
    assert len(paths) == 3


def test_finish_task_stages_cover_normal_path(mod) -> None:
    """``_FINISH_TASK_STAGES`` 가 14정상 경로 중 자동화 가능 8단계 모두 포함."""
    stages = mod._FINISH_TASK_STAGES
    src_states = {s for s, _ in stages}
    expected = {
        "COMMITTED",
        "PR_OPEN",
        "CI_PENDING",
        "GEMINI_PENDING",
        "REVIEW_READY",
        "VERIFIED",
        "HUMAN_APPROVED",
        "MERGED",
    }
    assert src_states == expected
