from __future__ import annotations

import json
from pathlib import Path
from types import SimpleNamespace

import pytest

from worai.errors import UsageError
from worai.structured_data import orchestrator as mod
from worai.structured_data.models import CreateRequest, GenerateRequest


def _create_request(tmp_path: Path, **overrides):
    base = dict(
        url="https://example.com",
        target_type="Thing",
        output_dir=tmp_path,
        base_name="sd",
        jsonld_path=None,
        yarrml_path=None,
        api_key="wl",
        base_url="https://api.wordlift.io",
        debug=False,
        headed=False,
        timeout_ms=1000,
        max_retries=0,
        quality_check=False,
        max_xhtml_chars=1000,
        max_text_node_chars=200,
        max_nesting_depth=1,
        verbose=False,
        validate=False,
        wait_until="load",
    )
    base.update(overrides)
    return CreateRequest(**base)


def test_create_workflow_error_and_debug_paths(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    wf = mod.CreateWorkflow(
        agent=SimpleNamespace(generate=lambda *_a, **_k: ("mappings: []", {"@type": "Thing"})),
        renderer=SimpleNamespace(render=lambda *_a, **_k: (SimpleNamespace(html="h", xhtml="x"), "x")),
        validator=SimpleNamespace(validate=lambda *_a, **_k: "ok"),
        engine=SimpleNamespace(get_dataset_uri=lambda *_a, **_k: "urn:dataset"),
    )

    with pytest.raises(UsageError, match="WORDLIFT_API_KEY"):
        wf.run(_create_request(tmp_path, api_key=None), log=lambda *_: None)
    with pytest.raises(UsageError, match="Base URL is required"):
        wf.run(_create_request(tmp_path, base_url=""), log=lambda *_: None)

    seen = {}
    monkeypatch.setattr(mod, "echo_debug", lambda *_a, **_k: seen.setdefault("debug", True))
    wf_bad = mod.CreateWorkflow(
        agent=SimpleNamespace(generate=lambda *_a, **_k: (_ for _ in ()).throw(RuntimeError("boom"))),
        renderer=SimpleNamespace(render=lambda *_a, **_k: (SimpleNamespace(html="h", xhtml="x"), "x")),
        validator=SimpleNamespace(validate=lambda *_a, **_k: "ok"),
        engine=SimpleNamespace(get_dataset_uri=lambda *_a, **_k: "urn:dataset"),
    )
    with pytest.raises(RuntimeError):
        wf_bad.run(_create_request(tmp_path, debug=True), log=lambda *_: None)
    assert seen.get("debug") is True


def test_create_workflow_verbose_warning_and_generate_workflow_errors(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    workdir = tmp_path / ".structured-data"
    workdir.mkdir(parents=True, exist_ok=True)
    (workdir / "mapping.validation.json").write_text(json.dumps({"warnings": ["reviewRating dropped from mapping"]}), encoding="utf-8")

    logs: list[str] = []
    wf = mod.CreateWorkflow(
        agent=SimpleNamespace(generate=lambda *_a, **_k: ("mappings: []", {"@type": "Thing"})),
        renderer=SimpleNamespace(render=lambda *_a, **_k: (SimpleNamespace(html="h", xhtml="x"), "x")),
        validator=SimpleNamespace(validate=lambda *_a, **_k: "ok"),
        engine=SimpleNamespace(get_dataset_uri=lambda *_a, **_k: "urn:dataset"),
    )
    wf.run(_create_request(tmp_path, verbose=True), log=lambda m: logs.append(m))
    assert any("reviewRating dropped" in m for m in logs)

    gw = mod.GenerateWorkflow(engine=SimpleNamespace(get_dataset_uri=lambda *_a, **_k: "urn:dataset"))
    with pytest.raises(UsageError, match="Base URL is required"):
        gw.run(
            GenerateRequest(
                input_value="https://e.com/sitemap.xml",
                yarrrml_path=tmp_path / "m.yarrrml",
                regex=".*",
                output_dir=tmp_path,
                output_format="ttl",
                concurrency="1",
                api_key="wl",
                base_url="",
                headed=False,
                timeout_ms=1000,
                wait_until="load",
                max_xhtml_chars=1000,
                max_text_node_chars=200,
                max_pages=None,
                verbose=False,
            ),
            log=lambda *_: None,
        )

    with pytest.raises(UsageError, match="WORDLIFT_API_KEY"):
        gw.run(
            GenerateRequest(
                input_value="https://e.com/sitemap.xml",
                yarrrml_path=tmp_path / "m.yarrrml",
                regex=".*",
                output_dir=tmp_path,
                output_format="ttl",
                concurrency="1",
                api_key=None,
                base_url="https://api.wordlift.io",
                headed=False,
                timeout_ms=1000,
                wait_until="load",
                max_xhtml_chars=1000,
                max_text_node_chars=200,
                max_pages=None,
                verbose=False,
            ),
            log=lambda *_: None,
        )

    with pytest.raises(UsageError, match="YARRRML file not found"):
        gw.run(
            GenerateRequest(
                input_value="https://e.com/sitemap.xml",
                yarrrml_path=tmp_path / "missing.yarrrml",
                regex=".*",
                output_dir=tmp_path,
                output_format="ttl",
                concurrency="1",
                api_key="wl",
                base_url="https://api.wordlift.io",
                headed=False,
                timeout_ms=1000,
                wait_until="load",
                max_xhtml_chars=1000,
                max_text_node_chars=200,
                max_pages=None,
                verbose=False,
            ),
            log=lambda *_: None,
        )

    monkeypatch.setenv("WORDLIFT_API_KEY", "wl_env")
    assert mod.resolve_api_key_from_context(None) == "wl_env"
