"""WES v1.1 API client."""

from __future__ import annotations

from typing import Any

from ai4gh.core.client import GA4GHClient
from ai4gh.specs.wes.models import RunDescription, RunId, RunListResponse, RunStatus


class WESClient(GA4GHClient):
    """Client for the GA4GH Workflow Execution Service (WES) v1.1.

    WES provides a standard API for submitting workflows to execution
    engines and monitoring their progress.
    """

    spec_name = "wes"
    spec_version = "1.1.0"
    base_path = "/ga4gh/wes/v1"

    async def submit_run(
        self,
        *,
        workflow_url: str,
        workflow_params: dict[str, Any] | None = None,
        workflow_type: str = "CWL",
        workflow_type_version: str = "v1.0",
        workflow_engine_parameters: dict[str, str] | None = None,
        tags: dict[str, str] | None = None,
    ) -> RunId:
        """Submit a workflow run.

        Args:
            workflow_url: URL to the workflow document.
            workflow_params: Input parameters for the workflow.
            workflow_type: Workflow language (CWL, WDL, Nextflow).
            workflow_type_version: Version of the workflow language.
            workflow_engine_parameters: Engine-specific parameters.
            tags: Key-value tags for the run.

        Returns:
            A RunId with the new run identifier.
        """
        body: dict[str, Any] = {
            "workflow_url": workflow_url,
            "workflow_type": workflow_type,
            "workflow_type_version": workflow_type_version,
        }
        if workflow_params is not None:
            body["workflow_params"] = workflow_params
        if workflow_engine_parameters is not None:
            body["workflow_engine_parameters"] = workflow_engine_parameters
        if tags is not None:
            body["tags"] = tags

        data = await self._request("POST", "/runs", json=body)
        return RunId.model_validate(data)

    async def get_run(self, run_id: str) -> RunDescription:
        """Get full details for a run.

        Args:
            run_id: The run identifier.

        Returns:
            Full run description including logs and outputs.
        """
        data = await self._request("GET", f"/runs/{run_id}")
        return RunDescription.model_validate(data)

    async def get_run_status(self, run_id: str) -> RunStatus:
        """Get the status of a run.

        Args:
            run_id: The run identifier.

        Returns:
            Minimal run status (id + state).
        """
        data = await self._request("GET", f"/runs/{run_id}/status")
        return RunStatus.model_validate(data)

    async def list_runs(
        self,
        *,
        page_size: int | None = None,
        page_token: str | None = None,
    ) -> RunListResponse:
        """List workflow runs.

        Args:
            page_size: Maximum number of runs to return.
            page_token: Token for pagination.

        Returns:
            List of run statuses with optional pagination token.
        """
        params: dict[str, Any] = {}
        if page_size is not None:
            params["page_size"] = page_size
        if page_token is not None:
            params["page_token"] = page_token
        data = await self._request("GET", "/runs", params=params or None)
        return RunListResponse.model_validate(data)

    async def cancel_run(self, run_id: str) -> RunId:
        """Cancel a running workflow.

        Args:
            run_id: The run identifier.

        Returns:
            The run ID of the cancelled run.
        """
        data = await self._request("POST", f"/runs/{run_id}/cancel")
        return RunId.model_validate(data)
