"""
Test Assignments Resource

PowerPath test assignment operations.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any
from urllib.parse import quote

from timeback_common import (
    Paginator,
    serialize_input,
    validate_non_empty_string,
    validate_with_schema,
)

from ..types.inputs import (
    TestAssignmentsAdminParams,
    TestAssignmentsBulkInput,
    TestAssignmentsCreateInput,
    TestAssignmentsImportInput,
    TestAssignmentsListParams,
    TestAssignmentsUpdateInput,
)
from ..types.responses import (
    AssignmentResult,
    BulkResult,
    TestAssignment,
    TestAssignmentsListResponse,
)

if TYPE_CHECKING:
    from ..lib.transport import Transport


class TestAssignmentsResource:
    """Test assignments resource for PowerPath APIs."""

    def __init__(self, transport: Transport) -> None:
        self._transport = transport

    @property
    def _base_path(self) -> str:
        return self._transport.paths.base

    def stream(
        self,
        params: TestAssignmentsListParams | dict[str, Any],
        *,
        max_items: int | None = None,
    ) -> Paginator[TestAssignment]:
        """
        Stream test assignments for a student with lazy pagination.

        Args:
            params: Query params (student required; supports limit/offset)
            max_items: Maximum items to fetch (None for unlimited)

        Returns:
            Paginator that yields TestAssignment items
        """
        validate_with_schema(TestAssignmentsListParams, params, "stream test assignments")
        query_params = serialize_input(params, TestAssignmentsListParams)
        limit = query_params.pop("limit", 100)
        return Paginator(
            self._transport,
            f"{self._base_path}/test-assignments",
            unwrap_key="testAssignments",
            params=query_params,
            limit=limit,
            max_items=max_items,
            transform=lambda item: TestAssignment.model_validate(item),
        )

    async def list_all(
        self,
        params: TestAssignmentsListParams | dict[str, Any],
        *,
        max_items: int | None = None,
    ) -> list[TestAssignment]:
        """Fetch all test assignments for a student."""
        return await self.stream(params, max_items=max_items).to_list()

    async def list(
        self, params: TestAssignmentsListParams | dict[str, Any]
    ) -> TestAssignmentsListResponse:
        """List test assignments with pagination metadata."""
        validate_with_schema(TestAssignmentsListParams, params, "list test assignments")
        body = await self._transport.get(
            f"{self._base_path}/test-assignments",
            params=serialize_input(params, TestAssignmentsListParams),
        )
        return TestAssignmentsListResponse.model_validate(body)

    async def create(self, input: TestAssignmentsCreateInput | dict[str, Any]) -> AssignmentResult:
        """Create a test assignment."""
        validate_with_schema(TestAssignmentsCreateInput, input, "test assignments create")
        body = await self._transport.post(
            f"{self._base_path}/test-assignments",
            serialize_input(input, TestAssignmentsCreateInput),
        )
        return AssignmentResult.model_validate(body)

    async def get(self, id: str) -> TestAssignment:
        """Get a single test assignment by ID."""
        validate_non_empty_string(id, "id")
        body = await self._transport.get(f"{self._base_path}/test-assignments/{quote(id, safe='')}")
        return TestAssignment.model_validate(body)

    async def update(
        self, id: str, input: TestAssignmentsUpdateInput | dict[str, Any]
    ) -> TestAssignment:
        """Update a test assignment."""
        validate_non_empty_string(id, "id")
        validate_with_schema(TestAssignmentsUpdateInput, input, "test assignments update")
        body = await self._transport.put(
            f"{self._base_path}/test-assignments/{quote(id, safe='')}",
            serialize_input(input, TestAssignmentsUpdateInput),
        )
        if body is None:
            return await self.get(id)
        return TestAssignment.model_validate(body)

    async def delete(self, id: str) -> None:
        """Delete a test assignment."""
        validate_non_empty_string(id, "id")
        await self._transport.delete(f"{self._base_path}/test-assignments/{quote(id, safe='')}")

    async def admin(
        self, params: TestAssignmentsAdminParams | dict[str, Any] | None = None
    ) -> TestAssignmentsListResponse:
        """List test assignments (admin view)."""
        if params is None:
            params = TestAssignmentsAdminParams()
        validate_with_schema(TestAssignmentsAdminParams, params, "list test assignments admin")
        body = await self._transport.get(
            f"{self._base_path}/test-assignments/admin",
            params=serialize_input(params, TestAssignmentsAdminParams),
        )
        return TestAssignmentsListResponse.model_validate(body)

    def admin_stream(
        self,
        params: TestAssignmentsAdminParams | dict[str, Any] | None = None,
        *,
        max_items: int | None = None,
    ) -> Paginator[TestAssignment]:
        """Stream all test assignments (admin) with lazy pagination."""
        if params is None:
            params = TestAssignmentsAdminParams()
        validate_with_schema(TestAssignmentsAdminParams, params, "stream test assignments admin")
        query_params = serialize_input(params, TestAssignmentsAdminParams)
        limit = query_params.pop("limit", 100)
        return Paginator(
            self._transport,
            f"{self._base_path}/test-assignments/admin",
            unwrap_key="testAssignments",
            params=query_params,
            limit=limit,
            max_items=max_items,
            transform=lambda item: TestAssignment.model_validate(item),
        )

    async def admin_list_all(
        self,
        params: TestAssignmentsAdminParams | dict[str, Any] | None = None,
        *,
        max_items: int | None = None,
    ) -> list[TestAssignment]:
        """Fetch all test assignments (admin)."""
        return await self.admin_stream(params, max_items=max_items).to_list()

    async def bulk(self, input: TestAssignmentsBulkInput | dict[str, Any]) -> BulkResult:
        """Bulk create test assignments."""
        validate_with_schema(TestAssignmentsBulkInput, input, "test assignments bulk")
        body = await self._transport.post(
            f"{self._base_path}/test-assignments/bulk",
            serialize_input(input, TestAssignmentsBulkInput),
        )
        return BulkResult.model_validate(body)

    async def import_assignments(
        self, input: TestAssignmentsImportInput | dict[str, Any]
    ) -> BulkResult:
        """Import test assignments from a spreadsheet."""
        validate_with_schema(TestAssignmentsImportInput, input, "test assignments import")
        body = await self._transport.post(
            f"{self._base_path}/test-assignments/import",
            serialize_input(input, TestAssignmentsImportInput),
        )
        return BulkResult.model_validate(body)
