from pathlib import Path

import pytest

from mnemosynecore.vault import client


def test_get_connection_as_json_from_env(monkeypatch):
    payload = '{"host":"env"}'
    monkeypatch.setenv("MY_CONN", payload)
    assert client.get_connection_as_json("MY_CONN") == payload


def test_get_connection_as_json_from_vault(monkeypatch):
    monkeypatch.delenv("MY_CONN", raising=False)
    monkeypatch.setattr(client.VaultClient, "get_secret", lambda self, key: '{"host":"vault"}')
    monkeypatch.setattr(client, "_airflow_connection_as_json", lambda key: '{"host":"airflow"}')
    assert client.get_connection_as_json("MY_CONN") == '{"host":"vault"}'


def test_get_connection_as_json_from_airflow(monkeypatch):
    monkeypatch.delenv("MY_CONN", raising=False)
    monkeypatch.setattr(client.VaultClient, "get_secret", lambda self, key: None)
    monkeypatch.setattr(client, "_airflow_connection_as_json", lambda key: '{"host":"airflow"}')
    assert client.get_connection_as_json("MY_CONN") == '{"host":"airflow"}'


def test_get_connection_as_json_raises_when_missing(monkeypatch):
    monkeypatch.delenv("MY_CONN", raising=False)
    monkeypatch.setattr(client.VaultClient, "get_secret", lambda self, key: None)
    monkeypatch.setattr(client, "_airflow_connection_as_json", lambda key: (_ for _ in ()).throw(ImportError()))
    with pytest.raises(ValueError, match="MY_CONN"):
        client.get_connection_as_json("MY_CONN")


def test_get_secret_parses_json(monkeypatch):
    monkeypatch.setattr(client, "get_connection_as_json", lambda _: '{"a": 1}')
    assert client.get_secret("X") == {"a": 1}


def test_get_secret_raises_on_invalid_json(monkeypatch):
    monkeypatch.setattr(client, "get_connection_as_json", lambda _: "not-json")
    with pytest.raises(ValueError, match="не является корректным JSON"):
        client.get_secret("X")


def test_get_connection_as_json_test_from_dir_path(tmp_path: Path):
    file = tmp_path / "BOT.json"
    file.write_text('{"x": 1}', encoding="utf-8")
    assert client.get_connection_as_json_test("BOT", dir_path=str(tmp_path)) == '{"x": 1}'


def test_get_connection_as_json_test_from_explicit_file_path(tmp_path: Path):
    file = tmp_path / "my_bot_creds.json"
    file.write_text('{"x": 3}', encoding="utf-8")
    assert client.get_connection_as_json_test("BOT", creds_path=str(file)) == '{"x": 3}'


def test_get_connection_as_json_test_from_cwd(monkeypatch, tmp_path: Path):
    file = tmp_path / "BOT.json"
    file.write_text('{"x": 2}', encoding="utf-8")
    monkeypatch.chdir(tmp_path)
    assert client.get_connection_as_json_test("BOT") == '{"x": 2}'


def test_get_connection_as_json_test_not_found(tmp_path: Path):
    with pytest.raises(FileNotFoundError, match="BOT.json"):
        client.get_connection_as_json_test("BOT", dir_path=str(tmp_path))


def test_get_secret_test_parses_json(monkeypatch):
    monkeypatch.setattr(client, "get_connection_as_json_test", lambda conn_id, dir_path=None: '{"a": 2}')
    assert client.get_secret_test("X") == {"a": 2}


def test_get_secret_test_parses_json_with_creds_path(monkeypatch):
    monkeypatch.setattr(
        client,
        "get_connection_as_json_test",
        lambda conn_id, dir_path=None, creds_path=None: '{"a": 5}',
    )
    assert client.get_secret_test("X", creds_path="/tmp/x.json") == {"a": 5}


def test_get_secret_test_raises_on_invalid_json(monkeypatch):
    monkeypatch.setattr(client, "get_connection_as_json_test", lambda conn_id, dir_path=None: "bad")
    with pytest.raises(ValueError, match="не является корректным JSON"):
        client.get_secret_test("X")


def test_has_connection(monkeypatch):
    monkeypatch.setattr(client, "get_connection_as_json", lambda name: "{}")
    assert client.has_connection("X") is True

    monkeypatch.setattr(client, "get_connection_as_json", lambda name: (_ for _ in ()).throw(ValueError("x")))
    assert client.has_connection("X") is False


def test_get_secret_field(monkeypatch):
    monkeypatch.setattr(client, "get_secret", lambda conn_id: {"a": {"b": 10}, "x": None})
    assert client.get_secret_field("CID", "a.b") == 10
    assert client.get_secret_field("CID", "a.c", default=5) == 5
    with pytest.raises(KeyError):
        client.get_secret_field("CID", "a.c", required=True)
    with pytest.raises(ValueError):
        client.get_secret_field("CID", "x", required=True)


def test_get_secret_field_test_mode(monkeypatch):
    monkeypatch.setattr(client, "get_secret_test", lambda conn_id, dir_path=None: {"a": 1})
    assert client.get_secret_field("CID", "a", test=True) == 1


def test_require_secret_fields(monkeypatch):
    monkeypatch.setattr(client, "get_secret", lambda conn_id: {"a": {"b": 1}, "x": "ok"})
    out = client.require_secret_fields("CID", ["a.b", "x"])
    assert out["x"] == "ok"

    monkeypatch.setattr(client, "get_secret", lambda conn_id: {"a": {"b": None}, "x": ""})
    with pytest.raises(ValueError, match="a.b"):
        client.require_secret_fields("CID", ["a.b", "x"])


def test_get_secret_with_defaults(monkeypatch):
    monkeypatch.setattr(client, "get_secret", lambda conn_id: {"b": 2})
    out = client.get_secret_with_defaults("CID", {"a": 1, "b": 0})
    assert out == {"a": 1, "b": 2}
