"""QTI client-side validation tests.

These mirror the TypeScript validation unit tests by asserting invalid inputs
fail before any transport request is made.
"""

from __future__ import annotations

import pytest

from timeback_common import InputValidationError
from timeback_qti.resources.assessment_items import AssessmentItemsResource
from timeback_qti.resources.assessment_tests import AssessmentTestsResource
from timeback_qti.resources.stimuli import StimuliResource


class _Paths:
    base = "https://example.test/api"


class _StubTransport:
    """Minimal transport stub that records whether requests were attempted."""

    def __init__(self) -> None:
        self.paths = _Paths()
        self.get_count = 0
        self.post_count = 0
        self.put_count = 0
        self.delete_count = 0

    async def get(self, _path: str, **_kwargs):  # type: ignore[no-untyped-def]
        self.get_count += 1
        raise AssertionError("get() should not be called for invalid input")

    async def post(self, _path: str, _body=None):  # type: ignore[no-untyped-def]
        self.post_count += 1
        raise AssertionError("post() should not be called for invalid input")

    async def put(self, _path: str, _body=None):  # type: ignore[no-untyped-def]
        self.put_count += 1
        raise AssertionError("put() should not be called for invalid input")

    async def delete(self, _path: str):  # type: ignore[no-untyped-def]
        self.delete_count += 1
        raise AssertionError("delete() should not be called for invalid input")


@pytest.mark.asyncio
async def test_assessment_items_validate_identifier_before_request() -> None:
    transport = _StubTransport()
    items = AssessmentItemsResource(transport)

    with pytest.raises(InputValidationError):
        await items.get("")

    assert transport.get_count == 0


@pytest.mark.asyncio
async def test_assessment_items_list_validates_params_before_request() -> None:
    transport = _StubTransport()
    items = AssessmentItemsResource(transport)

    with pytest.raises(InputValidationError):
        await items.list({"limit": 0})

    assert transport.get_count == 0


def test_assessment_items_stream_validates_params_before_pagination() -> None:
    transport = _StubTransport()
    items = AssessmentItemsResource(transport)

    with pytest.raises(InputValidationError):
        items.stream(max_items=0)


@pytest.mark.asyncio
async def test_assessment_tests_validate_identifier_before_request() -> None:
    transport = _StubTransport()
    tests = AssessmentTestsResource(transport)

    with pytest.raises(InputValidationError):
        await tests.get("")

    assert transport.get_count == 0


def test_assessment_tests_validate_nested_helper_ids() -> None:
    transport = _StubTransport()
    tests = AssessmentTestsResource(transport)

    with pytest.raises(InputValidationError):
        tests.test_parts("")

    with pytest.raises(InputValidationError):
        tests.test_parts("test").sections("")


@pytest.mark.asyncio
async def test_assessment_tests_list_validates_params_before_request() -> None:
    transport = _StubTransport()
    tests = AssessmentTestsResource(transport)

    with pytest.raises(InputValidationError):
        await tests.list({"limit": 0})

    assert transport.get_count == 0


@pytest.mark.asyncio
async def test_assessment_test_parts_list_validates_params_before_request() -> None:
    transport = _StubTransport()
    parts = AssessmentTestsResource(transport).test_parts("test")

    with pytest.raises(InputValidationError):
        await parts.list({"limit": 0})

    assert transport.get_count == 0


@pytest.mark.asyncio
async def test_assessment_sections_list_validates_params_before_request() -> None:
    transport = _StubTransport()
    sections = AssessmentTestsResource(transport).test_parts("test").sections("part")

    with pytest.raises(InputValidationError):
        await sections.list({"limit": 0})

    assert transport.get_count == 0


@pytest.mark.asyncio
async def test_stimuli_validate_identifier_before_request() -> None:
    transport = _StubTransport()
    stimuli = StimuliResource(transport)

    with pytest.raises(InputValidationError):
        await stimuli.get("")

    assert transport.get_count == 0


@pytest.mark.asyncio
async def test_stimuli_list_validates_params_before_request() -> None:
    transport = _StubTransport()
    stimuli = StimuliResource(transport)

    with pytest.raises(InputValidationError):
        await stimuli.list({"limit": 0})

    assert transport.get_count == 0
