"""htsget v1.3 API client."""

from __future__ import annotations

from typing import Any

from ai4gh.core.client import GA4GHClient
from ai4gh.specs.htsget.models import HtsgetClass, HtsgetFormat, HtsgetTicket


class HtsgetClient(GA4GHClient):
    """Client for the GA4GH htsget v1.3 API.

    htsget provides a ticket-based protocol for streaming genomic data.
    It supports reads (BAM/CRAM) and variants (VCF/BCF) endpoints with
    region-based subsetting.
    """

    spec_name = "htsget"
    spec_version = "1.3.0"
    base_path = ""

    async def get_reads(
        self,
        read_id: str,
        *,
        format: HtsgetFormat | None = None,
        data_class: HtsgetClass | None = None,
        reference_name: str | None = None,
        start: int | None = None,
        end: int | None = None,
        fields: list[str] | None = None,
        tags: list[str] | None = None,
        notags: list[str] | None = None,
    ) -> HtsgetTicket:
        """Get a reads ticket for BAM/CRAM data.

        Args:
            read_id: The read identifier.
            format: Desired response format (BAM or CRAM).
            data_class: Request header, body, or both.
            reference_name: Reference sequence name for region subsetting.
            start: Start position (0-based, inclusive).
            end: End position (0-based, exclusive).
            fields: List of BAM fields to include.
            tags: List of tags to include.
            notags: List of tags to exclude.

        Returns:
            An htsget ticket with URLs for downloading the data.
        """
        params = self._build_params(
            format=format,
            data_class=data_class,
            reference_name=reference_name,
            start=start,
            end=end,
            fields=fields,
            tags=tags,
            notags=notags,
        )
        data = await self._request("GET", f"/reads/{read_id}", params=params or None)
        return HtsgetTicket.model_validate(data)

    async def get_variants(
        self,
        variant_id: str,
        *,
        format: HtsgetFormat | None = None,
        data_class: HtsgetClass | None = None,
        reference_name: str | None = None,
        start: int | None = None,
        end: int | None = None,
    ) -> HtsgetTicket:
        """Get a variants ticket for VCF/BCF data.

        Args:
            variant_id: The variant identifier.
            format: Desired response format (VCF or BCF).
            data_class: Request header, body, or both.
            reference_name: Reference sequence name for region subsetting.
            start: Start position (0-based, inclusive).
            end: End position (0-based, exclusive).

        Returns:
            An htsget ticket with URLs for downloading the data.
        """
        params = self._build_params(
            format=format,
            data_class=data_class,
            reference_name=reference_name,
            start=start,
            end=end,
        )
        data = await self._request("GET", f"/variants/{variant_id}", params=params or None)
        return HtsgetTicket.model_validate(data)

    @staticmethod
    def _build_params(
        *,
        format: HtsgetFormat | None = None,
        data_class: HtsgetClass | None = None,
        reference_name: str | None = None,
        start: int | None = None,
        end: int | None = None,
        fields: list[str] | None = None,
        tags: list[str] | None = None,
        notags: list[str] | None = None,
    ) -> dict[str, Any]:
        """Build query parameters for htsget requests."""
        params: dict[str, Any] = {}
        if format is not None:
            params["format"] = format.value
        if data_class is not None:
            params["class"] = data_class.value
        if reference_name is not None:
            params["referenceName"] = reference_name
        if start is not None:
            params["start"] = start
        if end is not None:
            params["end"] = end
        if fields is not None:
            params["fields"] = ",".join(fields)
        if tags is not None:
            params["tags"] = ",".join(tags)
        if notags is not None:
            params["notags"] = ",".join(notags)
        return params
