from __future__ import annotations

import importlib.util
from pathlib import Path

import yaml


ROOT = Path(__file__).resolve().parents[2]
CONNECTOR = ROOT / "plugins" / "1c" / "connector"


def load_adapter():
    path = CONNECTOR / "adapter_1c_server.py"
    spec = importlib.util.spec_from_file_location("adapter_1c_policy_test", path)
    assert spec and spec.loader
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


def test_sql_base_access_policy_contract() -> None:
    policy = yaml.safe_load((CONNECTOR / "policies" / "sql-base-access-policy.yaml").read_text(encoding="utf-8"))
    assert policy["status"] == "active"
    assert policy["base_settings"]["selector"] == "base_id"
    assert set(policy["base_settings"]["required_fields"]) == {"server", "database", "user"}
    assert policy["read_scope"]["application_data"] == "read_only"
    assert policy["read_scope"]["metadata_structure"] == "read_only"
    assert set(policy["write_scope"]["allowed"].values()) == {"ConfigSave", "ConfigCASSave"}
    assert policy["sql_identity_management"]["mode"] == "forbidden"


def test_xml_is_offline_decoder_evidence_and_runtime_is_sql_only() -> None:
    policy = yaml.safe_load((CONNECTOR / "policies" / "xml-decoding-reference-policy.yaml").read_text(encoding="utf-8"))
    service = yaml.safe_load((CONNECTOR / "service.yaml").read_text(encoding="utf-8"))

    assert policy["status"] == "active"
    assert policy["offline_analysis"]["allowed"] is True
    assert policy["runtime"]["source"] == "sql_only"
    assert policy["runtime"]["xml_mount_required"] is False
    assert "policies/xml-decoding-reference-policy.yaml" in service["contracts"]["policies"]


def test_designer_sql_decoding_policy_keeps_adapter_read_only() -> None:
    policy = yaml.safe_load((CONNECTOR / "policies" / "designer-sql-decoding-policy.yaml").read_text(encoding="utf-8"))
    service = yaml.safe_load((CONNECTOR / "service.yaml").read_text(encoding="utf-8"))

    assert policy["scope"]["default_base_id"] == "upo_test"
    assert policy["scope"]["adapter_role"] == "specification_bound_sql_decoder_and_controlled_saved_state_writer"
    assert policy["credentials"]["persistence"] == "forbidden_in_repository"
    assert policy["sql_observation"]["adapter_access"] == "sql_only"
    assert "direct_application_data_write" in policy["sql_observation"]["forbidden"]
    assert policy["xml"]["role"] == "offline_schema_reference_only"
    assert "policies/designer-sql-decoding-policy.yaml" in service["contracts"]["policies"]


def test_runtime_rejects_xml_sources_at_any_payload_depth() -> None:
    adapter = load_adapter()

    direct = adapter.call_method_impl(
        "metadata.object.get",
        {"base_id": "upo_test", "ref": "Catalog.Test", "xml_path": "Configuration.xml"},
    )
    nested = adapter.call_method_impl(
        "metadata.write.plan",
        {"base_id": "upo_test", "target": {"form_xml_path": "Forms/Test/Ext/Form.xml"}},
    )

    assert direct["status"] == "invalid_argument"
    assert direct["argument"] == "payload.xml_path"
    assert nested["status"] == "invalid_argument"
    assert nested["argument"] == "payload.target.form_xml_path"
    assert "SQL-only" in direct["diagnostics"]["message"]


def test_adapter_has_no_xml_runtime_environment_configuration() -> None:
    source = (CONNECTOR / "adapter_1c_server.py").read_text(encoding="utf-8")
    assert "ONEC_XML" not in source


def test_sql_connection_requires_explicit_base_entry(monkeypatch) -> None:
    adapter = load_adapter()
    for name in (
        "ONEC_SQL_BASES_JSON",
        "ONEC_SQL_CONNECTIONS_JSON",
        "ONEC_SQL_BASES_JSON_FILE",
        "ONEC_SQL_CONNECTIONS_JSON_FILE",
    ):
        monkeypatch.delenv(name, raising=False)
    monkeypatch.setenv("ONEC_SQL_SERVER", "must-not-be-used")
    monkeypatch.setenv("ONEC_SQL_USER", "must-not-be-used")
    monkeypatch.setenv("ONEC_SQL_PASSWORD", "must-not-be-used")

    config, error = adapter.sql_config_for_base("upo_test")

    assert config is None
    assert error and error["status"] == "not_configured"


def test_sql_connection_does_not_infer_database_name(monkeypatch) -> None:
    adapter = load_adapter()
    monkeypatch.setenv(
        "ONEC_SQL_BASES_JSON",
        '{"upo_test":{"server":"sql-host","user":"login","password":"secret"}}',
    )

    config, error = adapter.sql_config_for_base("upo_test")

    assert config is None
    assert error and "database" in error["message"]


def test_sql_connection_ignores_legacy_connection_map(monkeypatch) -> None:
    adapter = load_adapter()
    monkeypatch.delenv("ONEC_SQL_BASES_JSON", raising=False)
    monkeypatch.delenv("ONEC_SQL_BASES_JSON_FILE", raising=False)
    monkeypatch.setenv(
        "ONEC_SQL_CONNECTIONS_JSON",
        '{"upo_test":{"server":"must-not-be-used","database":"must-not-be-used","user":"must-not-be-used","password":"must-not-be-used"}}',
    )

    config, error = adapter.sql_config_for_base("upo_test")

    assert config is None
    assert error and error["status"] == "not_configured"
    assert adapter.sql_configured_base_ids() == []
