from __future__ import annotations

import json
from types import SimpleNamespace

from typer.testing import CliRunner

from worai.commands import graph as graph_cmd
from worai.errors import UsageError


class _Result:
    def __init__(self, conforms: bool = True, warning_count: int = 0) -> None:
        self.conforms = conforms
        self.warning_count = warning_count


def test_graph_validate_uses_shape_resolver_and_validate_file(monkeypatch) -> None:
    seen = {}

    def _resolve(**kwargs):
        seen["resolve"] = kwargs
        return ["resolved-shape.ttl"]

    def _validate_file(input_file: str, shape_specs=None):
        seen.setdefault("calls", []).append((input_file, shape_specs))
        return _Result(conforms=True, warning_count=0)

    monkeypatch.setattr(graph_cmd, "_sdk_resolve_shape_specs", _resolve)
    monkeypatch.setattr(graph_cmd, "_sdk_validate_file", _validate_file)
    monkeypatch.setattr(graph_cmd, "_sdk_extract_validation_issues", lambda _r: [])
    monkeypatch.setattr(graph_cmd, "_sdk_filter_validation_issues", lambda issues, level: issues)

    result = CliRunner().invoke(
        graph_cmd.app,
        [
            "validate",
            "graph.ttl",
            "--builtin-shape",
            "google-required",
            "--exclude-builtin-shape",
            "schemaorg-grammar",
            "--shape",
            "./custom.ttl",
        ],
    )

    assert result.exit_code == 0
    assert seen["resolve"]["builtin_shapes"] == ["google-required"]
    assert seen["resolve"]["exclude_builtin_shapes"] == ["schemaorg-grammar"]
    assert seen["resolve"]["extra_shapes"] == ["./custom.ttl"]
    assert seen["calls"] == [("graph.ttl", ["resolved-shape.ttl"])]


def test_graph_validate_fails_at_warning_level(monkeypatch) -> None:
    monkeypatch.setattr(graph_cmd, "_sdk_resolve_shape_specs", lambda **_k: [])
    monkeypatch.setattr(graph_cmd, "_sdk_validate_file", lambda *_a, **_k: _Result(conforms=True, warning_count=1))
    issue = SimpleNamespace(
        level="warning",
        severity="Warning",
        focus_node="urn:focus",
        result_path="schema:name",
        rule_id="r1",
        rule_set="google",
        message="Missing recommended property",
    )
    monkeypatch.setattr(graph_cmd, "_sdk_extract_validation_issues", lambda _r: [issue])
    monkeypatch.setattr(
        graph_cmd,
        "_sdk_filter_validation_issues",
        lambda issues, level: issues if level == "warning" else [],
    )

    result = CliRunner().invoke(graph_cmd.app, ["validate", "graph.ttl", "--level", "warning"])

    assert result.exit_code == 1
    assert isinstance(result.exception, UsageError)
    assert "FAIL" in result.output


def test_graph_validate_error_level_ignores_warning_issues(monkeypatch) -> None:
    monkeypatch.setattr(graph_cmd, "_sdk_resolve_shape_specs", lambda **_k: [])
    monkeypatch.setattr(graph_cmd, "_sdk_validate_file", lambda *_a, **_k: _Result(conforms=True, warning_count=1))
    issue = SimpleNamespace(
        level="warning",
        severity="Warning",
        focus_node=None,
        result_path=None,
        rule_id="r1",
        rule_set="google",
        message="Missing recommended property",
    )
    monkeypatch.setattr(graph_cmd, "_sdk_extract_validation_issues", lambda _r: [issue])
    monkeypatch.setattr(
        graph_cmd,
        "_sdk_filter_validation_issues",
        lambda issues, level: issues if level == "warning" else [],
    )

    result = CliRunner().invoke(graph_cmd.app, ["validate", "graph.ttl", "--level", "error"])

    assert result.exit_code == 0
    assert "graph.ttl: OK" in result.output


def test_graph_validate_json_output_for_multiple_inputs(monkeypatch) -> None:
    monkeypatch.setattr(graph_cmd, "_sdk_resolve_shape_specs", lambda **_k: [])
    monkeypatch.setattr(graph_cmd, "_sdk_validate_file", lambda *_a, **_k: _Result(conforms=True, warning_count=0))
    monkeypatch.setattr(graph_cmd, "_sdk_extract_validation_issues", lambda _r: [])
    monkeypatch.setattr(graph_cmd, "_sdk_filter_validation_issues", lambda issues, level: issues)

    result = CliRunner().invoke(graph_cmd.app, ["validate", "a.ttl", "b.ttl", "--format", "json"])

    assert result.exit_code == 0
    payload = json.loads(result.output)
    assert isinstance(payload, list)
    assert [item["input"] for item in payload] == ["a.ttl", "b.ttl"]
    assert all(item["ok"] for item in payload)


def test_graph_validate_builtin_shapes_require_sdk_610(monkeypatch) -> None:
    monkeypatch.setattr(graph_cmd, "_sdk_resolve_shape_specs", None)

    result = CliRunner().invoke(graph_cmd.app, ["validate", "graph.ttl", "--builtin-shape", "google-required"])

    assert result.exit_code == 1
    assert isinstance(result.exception, UsageError)
    assert "wordlift-sdk>=6.1.0" in str(result.exception)
