"""doc_project：初始化、补丁、校验、快照、coverage、资源扫描、文本健康。"""

from __future__ import annotations

import json
from pathlib import Path

from aicd.tools.doc_project.kit import (
    SYSTEM_ATTRIBUTION,
    doc_manifest_coverage_report,
    doc_manifest_validate,
    doc_project_export,
    doc_revision_diff_summary,
    doc_text_health_check,
    get_doc_project,
    init_doc_project,
    library_doc_batch_quality_pass,
    library_doc_node_resolve,
    library_doc_snapshot,
    library_resources_scan,
    library_path,
    patch_doc_project,
)


def _policy(p: Path) -> None:
    return None


def test_init_get_patch_validate(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd"
    slug = "manual-test"
    r = init_doc_project(
        ai_out, slug, title="Test Manual", policy_check=_policy
    )
    assert r["ok"] is True
    lib = library_path(ai_out, slug)
    assert (lib / "doc_project.json").is_file()
    assert (lib / "resources").is_dir()

    g = get_doc_project(ai_out, slug, policy_check=_policy)
    assert g["ok"] is True
    assert g["manifest"]["doc_slug"] == slug

    tree = [
        {
            "node_id": "ch1",
            "title": "Chapter 1",
            "level": 1,
            "status": "draft",
            "content_paths": ["markdown/ch1.md"],
            "children": [],
        }
    ]
    (lib / "markdown" / "ch1.md").write_text("# Chapter 1\n\nHi\n", encoding="utf-8")
    pr = patch_doc_project(
        ai_out,
        slug,
        {"tree": tree, "title": "Test Manual v2"},
        policy_check=_policy,
    )
    assert pr["ok"] is True

    v = doc_manifest_validate(
        lib,
        json.loads((lib / "doc_project.json").read_text(encoding="utf-8")),
        check_paths_exist=True,
    )
    assert v["ok"] is True


def test_duplicate_node_id_fails_validation(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd2"
    slug = "dup"
    init_doc_project(ai_out, slug, title="d", policy_check=_policy)
    bad = {
        "schema_version": 1,
        "doc_slug": slug,
        "title": "x",
        "updated_at": "",
        "assembly": None,
        "style_profile_path": None,
        "tree": [
            {
                "node_id": "a",
                "title": "A",
                "level": 1,
                "status": "planned",
                "children": [{"node_id": "a", "title": "dup", "level": 2, "status": "planned"}],
            }
        ],
        "artifacts": {},
        "resources": [],
    }
    lib = library_path(ai_out, slug)
    v = doc_manifest_validate(lib, bad, check_paths_exist=False)
    assert v["ok"] is False
    assert any("duplicate" in e for e in v["errors"])


def test_snapshot_and_coverage(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd3"
    slug = "snap"
    init_doc_project(ai_out, slug, title="s", policy_check=_policy)
    lib = library_path(ai_out, slug)
    (lib / "markdown" / "orphan.md").write_text("# Orphan\n", encoding="utf-8")
    sn = library_doc_snapshot(ai_out, slug, policy_check=_policy)
    assert sn["ok"] is True
    snap_dir = Path(sn["snapshot_dir"])
    assert snap_dir.is_dir()
    assert (snap_dir / "doc_project.json").is_file()

    cov = doc_manifest_coverage_report(ai_out, slug, policy_check=_policy)
    assert cov["ok"] is True
    assert "markdown/orphan.md" in cov["unreferenced_markdown_files"]


def test_resources_scan_and_health(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd4"
    slug = "res"
    init_doc_project(ai_out, slug, title="r", policy_check=_policy)
    lib = library_path(ai_out, slug)
    (lib / "diagrams" / "a.txt").write_text("x", encoding="utf-8")
    (lib / "markdown" / "m.md").write_text("![](../diagrams/a.txt)\n", encoding="utf-8")
    rs = library_resources_scan(ai_out, slug, policy_check=_policy)
    assert rs["ok"] is True
    assert rs["entry_count"] >= 1
    idx = json.loads((lib / "resources" / "index.json").read_text(encoding="utf-8"))
    assert len(idx.get("entries", [])) >= 1

    h = doc_text_health_check(
        [lib / "markdown" / "m.md"], policy_check=_policy
    )
    assert h["ok"] is True
    assert h["files"][0].get("suspicious_mojibake") is False


def test_library_doc_node_resolve(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd5"
    slug = "node-res"
    init_doc_project(ai_out, slug, title="n", policy_check=_policy)
    lib = library_path(ai_out, slug)
    (lib / "markdown" / "x.md").write_text("# X\n", encoding="utf-8")
    patch_doc_project(
        ai_out,
        slug,
        {
            "tree": [
                {
                    "node_id": "n1",
                    "title": "One",
                    "level": 1,
                    "status": "draft",
                    "content_paths": ["markdown/x.md"],
                    "children": [],
                }
            ]
        },
        policy_check=_policy,
    )
    r = library_doc_node_resolve(ai_out, slug, "n1", policy_check=_policy)
    assert r["ok"] is True
    assert r["title"] == "One"
    assert len(r["content_paths_resolved"]) == 1
    assert r["content_paths_resolved"][0]["exists"] is True
    assert r["content_paths_resolved"][0]["rel"] == "markdown/x.md"

    miss = library_doc_node_resolve(ai_out, slug, "missing", policy_check=_policy)
    assert miss["ok"] is False


def test_doc_revision_diff_summary(tmp_path: Path) -> None:
    a = tmp_path / "before.md"
    b = tmp_path / "after.md"
    a.write_text("# Title\n\nOld\n", encoding="utf-8")
    b.write_text("# Title\n\nNew paragraph\n", encoding="utf-8")
    r = doc_revision_diff_summary(a, b, policy_check=_policy)
    assert r["ok"] is True
    assert r["sequencer_similarity"] > 0.5
    assert r["outline_delta"] is not None
    assert r["outline_delta"]["heading_count_before"] == r["outline_delta"]["heading_count_after"]


def test_library_doc_batch_quality_pass(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd6"
    slug = "batch"
    init_doc_project(ai_out, slug, title="b", policy_check=_policy)
    lib = library_path(ai_out, slug)
    (lib / "markdown" / "main.md").write_text("# Main\n\nOK 正文。\n", encoding="utf-8")
    patch_doc_project(
        ai_out,
        slug,
        {
            "tree": [
                {
                    "node_id": "root",
                    "title": "Root",
                    "level": 1,
                    "status": "draft",
                    "content_paths": ["markdown/main.md"],
                    "children": [],
                }
            ]
        },
        policy_check=_policy,
    )
    r = library_doc_batch_quality_pass(
        ai_out, slug, policy_check=_policy, scan_resources=False
    )
    assert r["ok"] is True
    assert r["attribution"] == SYSTEM_ATTRIBUTION
    assert "generated_at_utc" in r
    assert r["validate"].get("ok") is True
    assert r["coverage"].get("ok") is True


def test_doc_project_export_markdown_and_html(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd7"
    slug = "exp"
    topic = "topic-a"
    init_doc_project(ai_out, slug, title="e", policy_check=_policy)
    lib = library_path(ai_out, slug)
    (lib / "markdown" / "body.md").write_text("# Doc\n\nHello.\n", encoding="utf-8")
    r = doc_project_export(
        ai_out,
        doc_slug=slug,
        topic_slug=topic,
        source_markdown_rel="markdown/body.md",
        formats=["markdown", "html"],
        policy_check=_policy,
    )
    assert r["ok"] is True
    assert r["attribution"] == SYSTEM_ATTRIBUTION
    kinds = {o["format"] for o in r["outputs"]}
    assert "markdown" in kinds
    assert "html" in kinds
    deliv = Path(r["deliverables_dir"])
    assert deliv.is_dir()
    md_out = next(p for p in r["outputs"] if p["format"] == "markdown")
    text = Path(md_out["path"]).read_text(encoding="utf-8")
    assert SYSTEM_ATTRIBUTION in text
    assert "MANIFEST_" in Path(r["manifest_path"]).name
