from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "plugins" / "1c"))
sys.path.insert(0, str(ROOT / "plugins" / "1c" / "connector"))

import adapter_1c_server as adapter_server  # noqa: E402


def require(condition: bool, message: str, failures: list[str]) -> None:
    if not condition:
        failures.append(message)


def patch_adapter_for_symbol_checks() -> None:
    def fake_definition_find(payload: dict[str, Any]) -> dict[str, Any]:
        query = str(payload.get("query") or "")
        if query == "Артикул":
            return {
                "schema": "onec_definition_find.v1",
                "status": "ok",
                "matches": [
                    {
                        "canonical_path": "Справочник.Номенклатура.Артикул",
                        "kind": "Catalog",
                        "name": "Номенклатура",
                    }
                ],
            }
        if query == "Номенклатура":
            return {
                "schema": "onec_definition_find.v1",
                "status": "ok",
                "matches": [
                    {
                        "canonical_path": "Справочник.Номенклатура",
                        "kind": "Catalog",
                        "name": "Номенклатура",
                    }
                ],
            }
        return {"schema": "onec_definition_find.v1", "status": "ok", "matches": []}

    def fake_read_module(payload: dict[str, Any]) -> dict[str, Any]:
        return {
            "schema": "onec_module_read.v1",
            "status": "ok",
            "text": "Процедура ПередЗаписью(Отказ) Экспорт\n    Отказ = Истина;\nКонецПроцедуры",
            "owner": {"kind": "Catalog", "name": "Номенклатура"},
            "module": {"name": "Модуль объекта"},
        }

    def fake_attributes(payload: dict[str, Any]) -> dict[str, Any]:
        return {"schema": "onec_metadata_object_attributes.v1", "status": "ok", "attributes": []}

    adapter_server.metadata_definition_find = fake_definition_find
    adapter_server.read_module = fake_read_module
    adapter_server.metadata_object_attributes = fake_attributes


def check_full_path(failures: list[str]) -> None:
    result = adapter_server.call_method(
        "code.symbol.resolve",
        {
            "base_id": "upo_test",
            "expression": "Справочник.Номенклатура.Артикул",
            "module_ref": "ConfigSave:file:0",
        },
    )
    require(result.get("schema") == "onec_bsl_symbol_resolution.v1", "full path must return BSL symbol schema", failures)
    require(result.get("status") == "resolved", "full path must resolve", failures)
    require(result.get("resolution_kind") == "metadata_path", "full path must be classified as metadata_path", failures)
    require(result.get("canonical_path") == "Справочник.Номенклатура.Артикул", "full path must expose canonical_path publicly", failures)
    require(result.get("safe_as_metadata_path") is True, "full path must expose safe_as_metadata_path=true", failures)


def check_parameter(failures: list[str]) -> None:
    result = adapter_server.call_method(
        "code.symbol.resolve",
        {
            "base_id": "upo_test",
            "expression": "Отказ.Код",
            "routine_name": "ПередЗаписью",
            "module_ref": "ConfigSave:file:0",
        },
    )
    require(result.get("status") == "resolved", "routine parameter must resolve", failures)
    require(result.get("resolution_kind") == "parameter", "routine parameter must not be metadata", failures)
    require(result.get("context_path") == "Отказ.Код", "routine parameter must expose context_path publicly", failures)
    require(result.get("safe_as_metadata_path") is False, "routine parameter must expose safe_as_metadata_path=false", failures)


def check_short_name(failures: list[str]) -> None:
    result = adapter_server.call_method(
        "code.symbol.resolve",
        {
            "base_id": "upo_test",
            "expression": "Номенклатура.ЕдИзмерение.Код",
            "routine_name": "ПередЗаписью",
            "module_ref": "ConfigSave:file:0",
        },
    )
    candidates = result.get("candidates") if isinstance(result.get("candidates"), list) else []
    require(result.get("status") == "unresolved", "short object name must stay unresolved", failures)
    require(result.get("safe_as_metadata_path") is False, "short object name must expose safe_as_metadata_path=false", failures)
    require(bool(candidates), "short object name must return ambiguity candidates", failures)
    if candidates:
        require(candidates[0].get("canonical_path") == "Справочник.Номенклатура", "candidate canonical_path must stay public", failures)
        require(candidates[0].get("reason") == "short_object_name_requires_kind", "candidate must explain short name risk", failures)


def run_checks() -> dict[str, Any]:
    patch_adapter_for_symbol_checks()
    failures: list[str] = []
    check_full_path(failures)
    check_parameter(failures)
    check_short_name(failures)
    return {
        "schema": "onec_code_symbol_contract_check.v1",
        "status": "ok" if not failures else "failed",
        "failures": failures,
        "checks": {
            "full_path_metadata": "full path must resolve as metadata_path",
            "parameter_not_metadata": "routine parameter must not be metadata",
            "short_name_unsafe": "short object name must remain unsafe",
        },
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="Check adapter-level code.symbol.resolve contract invariants.")
    parser.add_argument("--print", action="store_true")
    args = parser.parse_args()
    report = run_checks()
    if args.print or report["status"] != "ok":
        print(json.dumps(report, ensure_ascii=False, indent=2))
    else:
        print("1C code symbol contract status: ok")
    return 0 if report["status"] == "ok" else 1


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