# 说明文字用的 #：入口脚本，支持多语言关于信息、JSON 输出、解释查询、快捷别名与全文检索（修复 __about__ 导入 & --search 兜底）

import argparse
import json
import datetime
import sys
import re
from pathlib import Path

SUPPORTED_LANGS = ["zh", "en", "fr", "de", "nl", "el", "la", "ja", "ko"]
LANG_NAMES = {
    "zh": "中文", "en": "English", "fr": "Français", "de": "Deutsch",
    "nl": "Nederlands", "el": "Ελληνικά", "la": "Latina", "ja": "日本語", "ko": "한국어",
}

SCHEMA_EXPLAIN = {
    "zh": {"title": "项目标题","version": "版本号","language": "输出语言代码","author": "作者信息字段集合","statements": "包含 purpose 与 legal_notice 的文本","support": "援助与联系方式字段集合","generated_at": "UTC 生成时间戳"},
    "en": {"title": "Project title","version": "Version number","language": "Output language code","author": "Author info object","statements": "Text fields purpose and legal_notice","support": "Support and contact object","generated_at": "UTC timestamp of generation"},
    "fr": {"title": "Titre du projet","version": "Numéro de version","language": "Code de langue de sortie","author": "Informations sur l’auteur","statements": "Champs texte purpose et legal_notice","support": "Objet d’aide et de contact","generated_at": "Horodatage UTC de génération"},
    "de": {"title": "Projekttitel","version": "Versionsnummer","language": "Ausgabesprachcode","author": "Autoreninformationen","statements": "Textfelder purpose und legal_notice","support": "Unterstützungs- und Kontaktangaben","generated_at": "UTC-Zeitstempel der Erzeugung"},
    "nl": {"title": "Projecttitel","version": "Versienummer","language": "Taalcode van de uitvoer","author": "Auteurinformatie","statements": "Tekstvelden purpose en legal_notice","support": "Ondersteuning en contact","generated_at": "UTC tijdstempel van generatie"},
    "el": {"title": "Τίτλος έργου","version": "Αριθμός έκδοσης","language": "Κωδικός γλώσσας εξόδου","author": "Στοιχεία συγγραφέα","statements": "Πεδία κειμένου purpose και legal_notice","support": "Πληροφορίες υποστήριξης και επικοινωνίας","generated_at": "Χρονική σφραγίδα UTC δημιουργίας"},
    "la": {"title": "Titulus propositi","version": "Numerus versionis","language": "Codex linguae pro output","author": "Notitia auctoris","statements": "Campi textuum purpose et legal_notice","support": "Auxilium et contactus","generated_at": "Tempus UTC generationis"},
    "ja": {"title": "プロジェクトタイトル","version": "バージョン番号","language": "出力言語コード","author": "著者情報オブジェクト","statements": "purpose と legal_notice のテキスト","support": "支援と連絡先の情報","generated_at": "生成の UTC タイムスタンプ"},
    "ko": {"title": "프로젝트 제목","version": "버전 번호","language": "출력 언어 코드","author": "저자 정보 객체","statements": "purpose 와 legal_notice 텍스트","support": "지원 및 연락처 정보","generated_at": "생성 UTC 타임스탬프"},
}

TEXT_EXTS = {".py", ".md", ".txt", ".toml", ".cfg", ".ini"}
IGNORE_DIRS = {"__pycache__", ".git", ".idea", ".vscode"}

def _stamp():
    return datetime.datetime.utcnow().isoformat() + "Z"

def _import_about():
    from importlib import import_module as _imp
    pkg = __package__ or (__name__.split('.')[0] if '.' in __name__ else "ai_language_filter")
    return _imp(f"{pkg}.__about__")

_HYPHENS = "-–—−－"
_WS = r"\s|\u00A0|\u3000"
_ALIAS_LANG_PAT = re.compile(rf"^[{_HYPHENS}]?\s*([a-z]{{2,3}})\s*$", re.IGNORECASE)
_ALIAS_SEARCH_PAT = re.compile(rf"^[{_HYPHENS}]?\s*([A-Za-z0-9_\-\.@]{{3,}})\s*$")

def _normalize_token(s: str) -> str:
    t = s
    for ch in _HYPHENS:
        t = t.replace(ch, "-")
    t = re.sub(rf"(?:{_WS})+", " ", t)
    return t.strip()

def _alias_rewrite(argv):
    if len(argv) <= 1:
        return argv
    toks = [_normalize_token(x) for x in argv[1:]]

    if len(toks) >= 2 and toks[0] == "-" and toks[1].lower() in SUPPORTED_LANGS:
        lang = toks[1].lower()
        want_json = any(x == "--json" for x in toks[2:])
        newargs = ["--about", "--lang", lang] + (["--json"] if want_json else [])
        return [argv[0]] + newargs
    m_lang = _ALIAS_LANG_PAT.match(toks[0])
    if m_lang and m_lang.group(1).lower() in SUPPORTED_LANGS:
        lang = m_lang.group(1).lower()
        want_json = any(x == "--json" for x in toks[1:])
        newargs = ["--about", "--lang", lang] + (["--json"] if want_json else [])
        return [argv[0]] + newargs

    if len(toks) == 1 and not toks[0].startswith("--"):
        m = _ALIAS_SEARCH_PAT.match(toks[0])
        if m:
            return [argv[0], "--search", m.group(1)]
    if len(toks) >= 2 and toks[0] == "-" and not toks[1].startswith("--"):
        m = _ALIAS_SEARCH_PAT.match(toks[1])
        if m:
            rest = [x for x in toks[2:] if x != "--"]
            return [argv[0], "--search", m.group(1)] + rest
    m2 = _ALIAS_SEARCH_PAT.match(toks[0])
    if m2 and m2.group(1).lower() not in SUPPORTED_LANGS:
        return [argv[0], "--search", m2.group(1)] + toks[1:]

    return argv

def cmd_about_text(lang: str):
    from . import about_texts
    purpose, legal = about_texts[lang]
    print(purpose.strip()); print(); print(legal.strip())

def cmd_about_json_one(lang: str):
    from . import about_json
    payload = about_json(lang); payload["generated_at"] = _stamp()
    print(json.dumps(payload, ensure_ascii=False, indent=2))

def cmd_about_json_all():
    from . import about_json_all
    payload = {"generated_at": _stamp(), "about": about_json_all()}
    print(json.dumps(payload, ensure_ascii=False, indent=2))

def cmd_list_langs(as_json: bool):
    rows = [{"code": c, "name": LANG_NAMES.get(c, c)} for c in SUPPORTED_LANGS]
    if as_json:
        print(json.dumps({"languages": rows}, ensure_ascii=False, indent=2))
    else:
        for r in rows:
            print(f"{r['code']}\t{r['name']}")

def cmd_explain(lang: str, as_json: bool):
    expl = SCHEMA_EXPLAIN.get(lang, SCHEMA_EXPLAIN["en"])
    if as_json:
        print(json.dumps({"language": lang, "schema": expl, "generated_at": _stamp()}, ensure_ascii=False, indent=2))
    else:
        print(f"language: {lang}")
        for k, v in expl.items():
            print(f"{k}: {v}")

def _pkg_paths():
    pkg_dir = Path(__file__).resolve().parent
    root_dir = pkg_dir.parent
    return pkg_dir, root_dir

def _iter_text_files():
    pkg_dir, root_dir = _pkg_paths()
    for base in (pkg_dir, root_dir):
        if not base.exists():
            continue
        for p in base.rglob("*"):
            if p.is_dir():
                if p.name in {"__pycache__", ".git", ".idea", ".vscode"}:
                    continue
                else:
                    continue
            if p.suffix.lower() in TEXT_EXTS or p.name.upper() == "LICENSE-NKZ.txt":
                yield p

def _make_terms_and_aliases(terms):
    extra = set()
    lowered = [t.lower() for t in terms]
    if any(t in {"nankehzhou", "nanke-zhou", "nanke_zhou"} for t in lowered) or any("nankehzhou" in t for t in lowered):
        extra.update(["nankezhou", "南柯舟", "dong@nankezhou.net", "nankezhou.net"])
    if any(t in {"nankezhou", "南柯舟"} for t in lowered):
        extra.update(["Nanke Zhou", "dong@nankezhou.net", "nankezhou.net"])
    return terms + list(extra)

def _grep_lines(text, terms, regex=False, ignore_case=True):
    flags = re.IGNORECASE if ignore_case else 0
    if regex:
        pat = re.compile(" ".join(terms), flags)
        for i, line in enumerate(text.splitlines(), start=1):
            m = pat.search(line)
            if m:
                yield i, line, [(m.start(), m.end())]
        return
    lowered_terms = [t.lower() for t in terms]
    for i, line in enumerate(text.splitlines(), start=1):
        ll = line.lower()
        if all(t in ll for t in lowered_terms):
            spans = []
            for t in lowered_terms:
                j = ll.find(t)
                if j >= 0:
                    spans.append((j, j + len(t)))
            yield i, line, spans

def cmd_search(terms, regex, context, limit, files_glob, as_json):
    terms = _make_terms_and_aliases(terms)
    hits = []
    count = 0
    globs = [g.lower() for g in files_glob] if files_glob else None

    for path in _iter_text_files():
        if globs:
            name = str(path).lower().replace("\\", "/")
            if not any(g in name for g in globs):
                continue
        try:
            text = path.read_text(encoding="utf-8", errors="ignore")
        except Exception:
            continue

        if "ai_language_filter/__about__.py" in str(path).replace("\\", "/").lower():
            ab = _import_about()
            about_blob = {
                "author": {
                    "name_cn": getattr(ab, "__author_name_cn__", "南柯舟"),
                    "name_en": getattr(ab, "__author_name_en__", "Nanke Zhou"),
                    "email": getattr(ab, "__author_email__", "dong@nankezhou.net"),
                    "website": getattr(ab, "__author_website__", "https://nankezhou.net"),
                    "birthdate": getattr(ab, "__author_birth__", "1975-07-17"),
                    "roles_cn": getattr(ab, "__author_roles_cn__", ""),
                    "roles_en": getattr(ab, "__author_roles_en__", ""),
                }
            }
        else:
            about_blob = None

        lines = text.splitlines()
        for i, line, spans in _grep_lines(text, terms, regex=regex):
            start_ctx = max(1, i - context)
            end_ctx = min(len(lines), i + context)
            snippet = "\n".join(lines[start_ctx-1:end_ctx])
            entry = {"file": str(path), "line": i, "snippet": snippet}
            if about_blob:
                entry["about"] = about_blob
            hits.append(entry)
            count += 1
            if count >= limit:
                break
        if count >= limit:
            break

    if as_json:
        print(json.dumps({"generated_at": _stamp(), "query": terms, "count": len(hits), "results": hits}, ensure_ascii=False, indent=2))
        return

    if not hits:
        print(f"[no results] query={terms}")
        return

    for h in hits:
        print(f"[{h['file']}:{h['line']}]")
        print(h["snippet"])
        if "about" in h:
            print(json.dumps(h["about"], ensure_ascii=False, indent=2))
        print()

def cmd_get(key: str, lang: str, all_langs: bool, as_json: bool):
    ab = _import_about()
    from . import about_texts
    def build_one(lc: str):
        purpose, legal = about_texts[lc]
        base = {
            "title": "AI Language Filter — LICENSE-NKZ",
            "version": getattr(ab, "__version__", "0.1.0-src"),
            "language": lc,
            "author": {
                "name_cn": getattr(ab, "__author_name_cn__", "南柯舟"),
                "name_en": getattr(ab, "__author_name_en__", "Nanke Zhou"),
                "email": getattr(ab, "__author_email__", "dong@nankezhou.net"),
                "website": getattr(ab, "__author_website__", "https://nankezhou.net"),
                "birthdate": getattr(ab, "__author_birth__", "1975-07-17"),
                "roles_cn": getattr(ab, "__author_roles_cn__", ""),
                "roles_en": getattr(ab, "__author_roles_en__", ""),
            },
            "statements": {"purpose": purpose, "legal_notice": legal},
            "support": {"paypal": getattr(ab, "__paypal__", "goodluck3658848@gmail.com")},
        }
        return {
            "purpose": {"language": lc, "purpose": purpose},
            "legal_notice": {"language": lc, "legal_notice": legal},
            "author": {"language": lc, "author": base["author"]},
            "support": {"language": lc, "support": base["support"]},
            "version": {"language": lc, "version": base["version"]},
            "title": {"language": lc, "title": base["title"]},
        }[key]
    if all_langs:
        out = {lc: build_one(lc) for lc in SUPPORTED_LANGS}
        if as_json:
            print(json.dumps({"generated_at": _stamp(), "get": key, "items": out}, ensure_ascii=False, indent=2))
        else:
            for lc, item in out.items():
                print(f"[{lc}]")
                for k, v in item.items():
                    if k != "language":
                        print(f"{k}: {v}")
                print()
        return
    item = build_one(lang)
    if as_json:
        item["generated_at"] = _stamp()
        print(json.dumps(item, ensure_ascii=False, indent=2))
    else:
        for k, v in item.items():
            if k != "language":
                print(f"{k}: {v}")

def main():
    sys.argv = _alias_rewrite(sys.argv)

    parser = argparse.ArgumentParser(
        prog="ai_language_filter",
        description="Language-data authenticity enforcement tool"
    )
    parser.add_argument("--version", action="store_true", help="print version and exit")
    parser.add_argument("--selftest", action="store_true", help="import FilterPipeline and run a tiny check")

    parser.add_argument("--about", action="store_true", help="print author and legal notices")
    parser.add_argument("--lang", choices=SUPPORTED_LANGS, default="zh", help="language for outputs")
    parser.add_argument("--json", action="store_true", help="output JSON for supported commands")
    parser.add_argument("--all-langs", dest="all_langs", action="store_true", help="with --about or --get in all languages")

    parser.add_argument("--list-langs", dest="list_langs", action="store_true", help="list supported languages")
    parser.add_argument("--explain", action="store_true", help="explain JSON schema fields")
    parser.add_argument("--get", choices=["purpose", "legal_notice", "author", "support", "version", "title"], help="return a specific field")

    # 说明文字用的 #：把 --search 改为可选参数列表，避免“至少一个参数”错误
    parser.add_argument("--search", nargs="*", help="full-text search terms across package files")
    parser.add_argument("--regex", action="store_true", help="treat --search terms as a single regex")
    parser.add_argument("--context", type=int, default=1, help="number of context lines for --search")
    parser.add_argument("--limit", type=int, default=200, help="max results for --search")
    parser.add_argument("--files", nargs="*", help="limit search to files whose paths contain these substrings")

    # 先宽松解析，捕获“游离参数”作为 --search 的补充
    args, unknown = parser.parse_known_args()
    if args.search is not None and len(args.search) == 0 and unknown:
        args.search = [u for u in unknown if not u.startswith("--")]

    if args.version:
        print("ai_language_filter 0.1.0-src"); return

    if args.selftest:
        from . import FilterPipeline
        fp = FilterPipeline()
        print({"ok": True, "has_pipeline": hasattr(fp, "run")})
        return

    if args.list_langs:
        cmd_list_langs(as_json=args.json); return

    if args.explain:
        cmd_explain(lang=args.lang, as_json=args.json); return

    if args.get:
        cmd_get(key=args.get, lang=args.lang, all_langs=args.all_langs, as_json=args.json); return

    if args.search is not None:
        if len(args.search) == 0:
            parser.error("argument --search: requires at least one search term")
        cmd_search(terms=args.search, regex=args.regex, context=args.context, limit=args.limit, files_glob=args.files, as_json=args.json); return

    if args.about:
        if args.json:
            cmd_about_json_all() if args.all_langs else cmd_about_json_one(args.lang)
        else:
            cmd_about_text(args.lang)
        return

    parser.print_help()

if __name__ == "__main__":
    main()
