from __future__ import annotations

import json
from pathlib import Path

from aicd.tools.code_gen_tree import (
    build_scan_payload,
    python_file_gen_tree,
    write_gen_tree_json,
)
from aicd.tools.code_gen_tree_query import query_tree
from aicd.tools.code_gen_tree_store import read_manifest, write_versioned_tree


def test_python_file_nested(tmp_path: Path) -> None:
    p = tmp_path / "m.py"
    p.write_text(
        '"""mod doc."""\n'
        "class A:\n"
        '    """cla."""\n'
        "    def m(self):\n"
        "        def inner():\n"
        "            pass\n"
        "        pass\n",
        encoding="utf-8",
    )
    out = python_file_gen_tree(p)
    assert out["ok"] is True
    kinds = [n["kind"] for n in out["nodes"]]
    assert kinds[0] == "module"
    assert "class" in kinds
    assert "function" in kinds
    qnames = {n["qname"] for n in out["nodes"]}
    # module_qname defaults to file stem → "m" for m.py
    assert "m.A.m.inner" in qnames
    mod = out["nodes"][0]
    assert mod["parent_id"] is None
    assert mod["docstring_preview"] == "mod doc."
    assert mod.get("parser") == "ast"


def test_build_scan_payload_dir(tmp_path: Path) -> None:
    pkg = tmp_path / "pkg"
    pkg.mkdir()
    (pkg / "__init__.py").write_text("# x\n", encoding="utf-8")
    (pkg / "util.py").write_text("def f():\n    pass\n", encoding="utf-8")
    pl = build_scan_payload(tmp_path, recursive=True, max_files=50)
    assert pl["ok"] is True
    assert pl["files_scanned"] == 2
    qn = {n["qname"] for n in pl["nodes"]}
    assert "pkg.util.f" in qn
    assert "python" in pl["languages"]


def test_write_gen_tree_json(tmp_path: Path) -> None:
    p = tmp_path / "a.py"
    p.write_text("def x():\n    pass\n", encoding="utf-8")
    payload = build_scan_payload(p, max_files=10)
    dest = tmp_path / "tree.json"
    wr = write_gen_tree_json(payload, dest)
    assert wr["ok"] is True
    data = json.loads(dest.read_text(encoding="utf-8"))
    assert data["schema"] == "aicd_code_gen_tree"
    assert "generated_at" in data


def test_go_polyglot(tmp_path: Path) -> None:
    (tmp_path / "main.go").write_text(
        "package main\n\nfunc main() {}\n",
        encoding="utf-8",
    )
    pl = build_scan_payload(tmp_path, max_files=10, scan_profile="polyglot")
    assert pl["ok"] is True
    assert "go" in pl["languages"]
    qn = {n["qname"] for n in pl["nodes"]}
    assert any("main" in q for q in qn)


def test_versioned_store_and_query(tmp_path: Path) -> None:
    ai_out = tmp_path / "aicd"
    src = tmp_path / "src"
    src.mkdir()
    (src / "a.py").write_text("def foo():\n    pass\n", encoding="utf-8")
    payload = build_scan_payload(src, max_files=10)
    st = write_versioned_tree(ai_out, "mytopic", payload, scan_root=str(src))
    assert st["index_revision"] == 1
    man = read_manifest(ai_out, "mytopic")
    assert man is not None
    assert man["latest_revision"] == 1
    tree_path = Path(st["tree_json_path"])
    stats = query_tree(tree_path, action="stats")
    assert stats["ok"] is True
    assert stats["meta"]["total_nodes"] >= 2
    st2 = write_versioned_tree(ai_out, "mytopic", payload, scan_root=str(src))
    assert st2["index_revision"] == 2


def test_query_children(tmp_path: Path) -> None:
    p = tmp_path / "x.py"
    p.write_text("class A:\n    def m(self):\n        pass\n", encoding="utf-8")
    payload = build_scan_payload(p, max_files=5)
    dest = tmp_path / "t.json"
    write_gen_tree_json(payload, dest)
    data = json.loads(dest.read_text(encoding="utf-8"))
    mod_id = next(n["id"] for n in data["nodes"] if n["kind"] == "module")
    ch = query_tree(dest, action="children", parent_id=mod_id, limit=50)
    assert ch["ok"] is True
    assert ch["returned"] >= 1
