"""
模块入口：

  python -m locateagent --query "我想定位数据云端下发的接口"

默认读取当前目录的：
- project_map.json（FileAtlas 输出）
- architecture.json（可选；ModuleAtlas 输出，用于 file->module 映射与模块信息）

并输出一个“相关文件 + 可能接口符号 + 行号范围”的报告。
"""

from __future__ import annotations

import argparse
import json

from .runner import LocateAgentConfig, locate_query


def _parse_args() -> LocateAgentConfig:
    p = argparse.ArgumentParser(prog="locateagent", add_help=True)
    p.add_argument("--query", required=True, help="Natural language query, e.g. '云端下发接口'")
    p.add_argument("--project-map", default="project_map.json", help="Path to project_map.json from FileAtlas")
    p.add_argument("--architecture-json", default="architecture.json", help="Path to architecture.json from ModuleAtlas (optional)")
    p.add_argument("--top-files", type=int, default=8, help="How many files to return")
    p.add_argument("--top-symbols", type=int, default=6, help="How many symbol candidates per file")
    p.add_argument("--min-score", type=float, default=0.0, help="Filter out candidates below this score")
    p.add_argument("--recall", choices=["llm", "heuristic", "hybrid"], default="hybrid", help="Recall strategy")
    p.add_argument("--llm-recall-max-modules", type=int, default=8, help="How many modules to select in LLM recall")
    p.add_argument("--llm-recall-max-files", type=int, default=12, help="How many files to select in LLM recall")
    p.add_argument("--llm-recall-file-digest-limit", type=int, default=220, help="Max file digests sent to LLM recall (cap prompt size)")
    p.add_argument("--llm-recall-nonstrict", action="store_true", help="Allow falling back to heuristic recall if LLM recall fails")
    p.add_argument("--no-llm", action="store_true", help="Disable LLM refinement stage (use only heuristic retrieval)")
    p.add_argument("--llm-concurrency", type=int, default=2, help="Concurrent LLM file refinements")
    p.add_argument("--llm-max-files", type=int, default=6, help="How many top files to run LLM refinement on")
    p.add_argument("--llm-max-symbols", type=int, default=12, help="How many symbols per file to send as evidence")
    p.add_argument("--llm-max-excerpt-tokens", type=int, default=2200, help="Total excerpt token budget per file evidence")
    p.add_argument("--format", choices=["markdown", "json"], default="markdown", help="Output format")
    args = p.parse_args()
    return LocateAgentConfig(
        query=str(args.query),
        project_map_path=str(args.project_map),
        architecture_json_path=str(args.architecture_json),
        top_files=int(args.top_files),
        top_symbols=int(args.top_symbols),
        min_score=float(args.min_score),
        out_format=str(args.format),
        llm_enabled=not bool(args.no_llm),
        llm_concurrency=int(args.llm_concurrency),
        llm_max_files=int(args.llm_max_files),
        llm_max_symbols_per_file=int(args.llm_max_symbols),
        llm_max_excerpt_tokens=int(args.llm_max_excerpt_tokens),
        recall_mode=str(args.recall),
        llm_recall_max_modules=int(args.llm_recall_max_modules),
        llm_recall_max_files=int(args.llm_recall_max_files),
        llm_recall_file_digest_limit=int(args.llm_recall_file_digest_limit),
        llm_recall_strict=not bool(args.llm_recall_nonstrict),
    )


def main() -> int:
    cfg = _parse_args()
    result = locate_query(cfg)
    if cfg.out_format == "json":
        print(json.dumps(result, ensure_ascii=False, indent=2))
    else:
        print(result.get("markdown", ""))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

