from __future__ import annotations

import json
from pathlib import Path

import pytest

from worai.core import upload_entities_from_turtle as mod


@pytest.mark.asyncio
async def test_upload_entities_success_failure_and_skip(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    folder = tmp_path / "in"
    folder.mkdir()

    ok = folder / "a.ttl"
    ok.write_text("<s> <p> <o> .", encoding="utf-8")
    empty = folder / "b.ttl"
    empty.write_text("   ", encoding="utf-8")
    skipped = folder / "c.ttl"
    skipped.write_text("<x> <p> <o> .", encoding="utf-8")

    state_path = tmp_path / "state.json"
    state_path.write_text(json.dumps({"processed": ["c.ttl"], "failed": {}}), encoding="utf-8")

    class _ApiClient:
        def __init__(self, _config):
            pass

        async def __aenter__(self):
            return self

        async def __aexit__(self, *_args):
            return None

    class _EntitiesApi:
        def __init__(self, _client) -> None:
            pass

        async def create_or_update_entities(self, content: str, _content_type: str) -> None:
            assert _content_type == "text/turtle"
            if "<s>" in content:
                return None
            raise AssertionError("unexpected")

    monkeypatch.setattr(mod, "ApiClient", _ApiClient)
    monkeypatch.setattr(mod.wordlift_client, "EntitiesApi", _EntitiesApi)
    monkeypatch.setattr(mod, "tqdm", lambda items, **_kwargs: items)

    rc = await mod.upload_entities(
        folder,
        [ok, empty, skipped],
        "wl_key",
        "https://api.wordlift.io",
        state_path,
    )
    assert rc == 2

    state = json.loads(state_path.read_text(encoding="utf-8"))
    assert "a.ttl" in state["processed"]
    assert "b.ttl" in state["failed"]
    assert "c.ttl" in state["processed"]


def test_gather_load_save_relpath_and_run(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    folder = tmp_path / "in"
    folder.mkdir()
    nested = folder / "n"
    nested.mkdir()
    (folder / "x.ttl").write_text("x", encoding="utf-8")
    (nested / "y.turtle").write_text("y", encoding="utf-8")
    (folder / "z.txt").write_text("z", encoding="utf-8")

    files_non_recursive = mod.gather_files(folder, recursive=False, extensions=mod.DEFAULT_EXTENSIONS)
    assert [p.name for p in files_non_recursive] == ["x.ttl"]

    files_recursive = mod.gather_files(folder, recursive=True, extensions=mod.DEFAULT_EXTENSIONS)
    assert sorted(p.name for p in files_recursive) == ["x.ttl", "y.turtle"]

    missing_state = mod.load_state(tmp_path / "missing.json")
    assert missing_state == {"processed": [], "failed": {}}

    bad = tmp_path / "bad.json"
    bad.write_text("[]", encoding="utf-8")
    assert mod.load_state(bad) == {"processed": [], "failed": {}}

    state_path = tmp_path / "state.json"
    mod.save_state(state_path, {"processed": ["x.ttl"], "failed": {}})
    assert json.loads(state_path.read_text(encoding="utf-8"))["processed"] == ["x.ttl"]

    assert mod.relpath(folder / "x.ttl", folder) == "x.ttl"
    assert mod.relpath(Path("/tmp/other.ttl"), folder).endswith("other.ttl")

    with pytest.raises(RuntimeError, match="No Turtle files found"):
        mod.run(mod.UploadOptions(folder=tmp_path / "empty", api_key="k"))


def test_run_nothing_to_do_and_limit(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    folder = tmp_path / "in"
    folder.mkdir()
    a = folder / "a.ttl"
    b = folder / "b.ttl"
    a.write_text("a", encoding="utf-8")
    b.write_text("b", encoding="utf-8")

    state_path = folder / ".entities_upload_state.json"
    state_path.write_text(json.dumps({"processed": ["a.ttl", "b.ttl"], "failed": {}}), encoding="utf-8")
    assert mod.run(mod.UploadOptions(folder=folder, api_key="k")) == 0

    state_path.write_text(json.dumps({"processed": [], "failed": {}}), encoding="utf-8")
    seen: dict[str, object] = {}

    async def _fake_upload(folder, files, api_key, base_url, state_path):
        seen["files"] = files
        seen["api_key"] = api_key
        return 0

    monkeypatch.setattr(mod, "upload_entities", _fake_upload)

    rc = mod.run(mod.UploadOptions(folder=folder, api_key="k", limit=1))
    assert rc == 0
    assert len(seen["files"]) == 1
    assert seen["api_key"] == "k"
