#!/usr/bin/env python3
"""L0 — статический анализ BSL через BSL Language Server (офлайн, ~10 с).

Блокирует только то, что ломает компиляцию: ошибки разбора (ParseError).
Остальные диагностики (стандарты 1С, сложность, стиль) идут в отчёт
справочно — иначе legacy-код заказчика не пройдёт гейт никогда.

Использование: lint_bsl.py <каталог с .bsl> [--json <файл>]
Код возврата: 0 — блокирующих нет, 1 — есть.
"""
from __future__ import annotations

import collections
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path

JAR = Path(os.environ.get(
    "BSL_LS_JAR",
    str(Path.home() / ".local/share/bsl-language-server/bsl-language-server.jar")))
JAVA = os.environ.get("BSL_LS_JAVA", "/opt/homebrew/opt/openjdk@21/bin/java")

# Диагностики, означающие «этот модуль не скомпилируется».
BLOCKING_CODES = {"ParseError"}


def analyze(src: Path) -> dict:
    if not JAR.exists():
        raise SystemExit(f"нет BSL LS: {JAR} (см. tools/setup.sh)")
    work = Path(tempfile.mkdtemp(prefix="bslls_", dir="/tmp"))
    proc = subprocess.run(
        [JAVA, "-jar", str(JAR), "--analyze", "--srcDir", str(src),
         "--reporter", "json"],
        cwd=work, capture_output=True, text=True, timeout=1800, check=False)
    report = work / "bsl-json.json"
    if not report.exists():
        raise SystemExit(f"BSL LS не создал отчёт:\n{proc.stdout[-2000:]}"
                         f"\n{proc.stderr[-2000:]}")
    data = json.loads(report.read_text(encoding="utf-8"))
    blocking, counts = [], collections.Counter()
    for fi in data.get("fileinfos", []):
        rel = fi.get("path", "")
        for d in fi.get("diagnostics", []):
            code = d.get("code")
            if isinstance(code, dict):
                code = code.get("left") or code.get("right")
            counts[d.get("severity", "?")] += 1
            if code in BLOCKING_CODES:
                msg = d.get("message")
                if isinstance(msg, dict):
                    msg = msg.get("left") or msg.get("right")
                blocking.append({
                    "file": rel,
                    "line": d["range"]["start"]["line"] + 1,
                    "column": d["range"]["start"]["character"] + 1,
                    "code": code,
                    "message": (msg or "").strip(),
                })
    return {"blocking": blocking, "counts": dict(counts),
            "raw_report": str(report)}


def main() -> int:
    src = Path(sys.argv[1]).resolve()
    res = analyze(src)
    if "--json" in sys.argv:
        target = Path(sys.argv[sys.argv.index("--json") + 1])
        target.write_text(json.dumps(res, ensure_ascii=False, indent=2),
                          encoding="utf-8")
    if res["blocking"]:
        print(f"L0 FAIL — ошибок разбора: {len(res['blocking'])}")
        for b in res["blocking"]:
            print(f"  {Path(b['file']).name}:{b['line']}:{b['column']} "
                  f"{b['code']} — {b['message'][:140]}")
    else:
        print("L0 OK — ошибок разбора нет")
    other = {k: v for k, v in res["counts"].items() if v}
    if other:
        print(f"  справочно (не блокирует): {other}")
        print(f"  полный отчёт: {res['raw_report']}")
    return 1 if res["blocking"] else 0


if __name__ == "__main__":
    sys.exit(main())
