"""Slices Project API."""

from datetime import datetime
from typing import Annotated

from httpx import Client, HTTPError
from msgspec import Meta, Struct
from msgspec.json import Decoder as JsonDecoder

from slices_clientlib_core.base.exceptions import from_httpx_exception


class Project(Struct):
    """Project."""

    created_at: Annotated[datetime, Meta(tz=True)]

    description: str | None
    expires_at: Annotated[datetime, Meta(tz=True)] | None
    id: str
    name: str
    role: str


_project_decoder = JsonDecoder(Project)


class ProjectList(Struct):
    """List of projects."""

    projects: list[Project]


_project_list_decoder = JsonDecoder(ProjectList)


class ProjectMember(Struct):
    """Project Member."""

    role: str
    user_id: str


class ProjectMemberList(Struct):
    """List of project members."""

    project_members: list[ProjectMember]


_project_member_list_decoder = JsonDecoder(ProjectMemberList)


class ProjectClient:
    """Project Client."""

    API_BASE_PATH = "/apis/proj.slices-ri.eu/v1/projects/"

    def __init__(self, client: Client) -> None:
        """Create Project Client."""
        self._client = client

        assert client.base_url is not None, "Expected base_url to be set"

    def get(self, id: str) -> Project:
        """Get project by ID."""
        response = self._client.get(f"{self.API_BASE_PATH}{id}")

        try:
            response.raise_for_status()
            return _project_decoder.decode(response.content)
        except HTTPError as err:
            raise from_httpx_exception(err) from err

    def get_jwt(self, id: str) -> str:
        """Get project JWT."""
        response = self._client.get(f"{self.API_BASE_PATH}{id}", headers={"Accept": "application/jwt"})

        try:
            response.raise_for_status()
        except HTTPError as err:
            raise from_httpx_exception(err) from err
        else:
            return response.text

    def list_members(self, id: str) -> list[ProjectMember]:
        """List project members."""
        params = {}
        response = self._client.get(f"{self.API_BASE_PATH}{id}/members", params=params)

        try:
            response.raise_for_status()
            return _project_member_list_decoder.decode(response.content).project_members
        except HTTPError as err:
            raise from_httpx_exception(err) from err

    def list(self, include_expired: bool | None = None) -> list[Project]:
        """List projects."""
        params = {}
        if include_expired is not None:
            params["include_expired"] = str(include_expired).lower()
        response = self._client.get(self.API_BASE_PATH, params=params)

        try:
            response.raise_for_status()
            return _project_list_decoder.decode(response.content).projects
        except HTTPError as err:
            raise from_httpx_exception(err) from err
