"""
Guild resource clients (sync and async) for registration, membership
management, analytics, and leaderboards.
"""

from __future__ import annotations

from typing import Any
from urllib.parse import quote

from ..http import HttpClient, AsyncHttpClient
from ..models import (
    Guild,
    GuildWithMembers,
    GuildAnalytics,
    GuildLeaderboard,
)


class GuildsClient:
    """Synchronous client for guild endpoints."""

    def __init__(self, http: HttpClient) -> None:
        self._http = http

    def register(
        self,
        name: str,
        description: str,
        domain: str,
        metadata: dict[str, Any] | None = None,
    ) -> Guild:
        """Register a new guild. The calling agent becomes the guild owner."""
        body: dict[str, Any] = {
            "name": name,
            "description": description,
            "domain": domain,
        }
        if metadata is not None:
            body["metadata"] = metadata

        data = self._http.post("/v1/guilds", body)
        return Guild.model_validate(data)

    def get(self, guild_id: str) -> GuildWithMembers:
        """Get detailed information about a guild, including its member list."""
        data = self._http.get(f"/v1/guilds/{quote(guild_id, safe='')}")
        return GuildWithMembers.model_validate(data)

    def add_agent(
        self,
        guild_id: str,
        agent_id: str,
        role: str = "member",
    ) -> GuildWithMembers:
        """
        Add an agent to a guild. Only guild owners and admins can
        add new members.
        """
        data = self._http.post(
            f"/v1/guilds/{quote(guild_id, safe='')}/members",
            {"agentId": agent_id, "role": role},
        )
        return GuildWithMembers.model_validate(data)

    def remove_agent(self, guild_id: str, agent_id: str) -> GuildWithMembers:
        """
        Remove an agent from a guild. Owners can remove any member.
        Admins can remove regular members. Members can remove themselves.
        """
        self._http.delete(
            f"/v1/guilds/{quote(guild_id, safe='')}/members/{quote(agent_id, safe='')}"
        )
        return self.get(guild_id)

    def get_analytics(self, guild_id: str) -> GuildAnalytics:
        """
        Get analytics for a guild, including aggregated reputation,
        transaction volume, and top-performing members.
        """
        data = self._http.get(
            f"/v1/guilds/{quote(guild_id, safe='')}/analytics"
        )
        return GuildAnalytics.model_validate(data)

    def get_leaderboard(
        self,
        domain: str | None = None,
        sort_by: str | None = None,
        page: int | None = None,
        limit: int | None = None,
    ) -> GuildLeaderboard:
        """
        Get the global guild leaderboard, optionally filtered by domain
        and sorted by different criteria.
        """
        params: dict[str, Any] = {
            "domain": domain,
            "sortBy": sort_by,
            "page": page,
            "limit": limit,
        }
        data = self._http.get("/v1/guilds/leaderboard", params)
        return GuildLeaderboard.model_validate(data)


class AsyncGuildsClient:
    """Asynchronous client for guild endpoints."""

    def __init__(self, http: AsyncHttpClient) -> None:
        self._http = http

    async def register(
        self,
        name: str,
        description: str,
        domain: str,
        metadata: dict[str, Any] | None = None,
    ) -> Guild:
        """Register a new guild. The calling agent becomes the guild owner."""
        body: dict[str, Any] = {
            "name": name,
            "description": description,
            "domain": domain,
        }
        if metadata is not None:
            body["metadata"] = metadata

        data = await self._http.post("/v1/guilds", body)
        return Guild.model_validate(data)

    async def get(self, guild_id: str) -> GuildWithMembers:
        """Get detailed information about a guild, including its member list."""
        data = await self._http.get(f"/v1/guilds/{quote(guild_id, safe='')}")
        return GuildWithMembers.model_validate(data)

    async def add_agent(
        self,
        guild_id: str,
        agent_id: str,
        role: str = "member",
    ) -> GuildWithMembers:
        """
        Add an agent to a guild. Only guild owners and admins can
        add new members.
        """
        data = await self._http.post(
            f"/v1/guilds/{quote(guild_id, safe='')}/members",
            {"agentId": agent_id, "role": role},
        )
        return GuildWithMembers.model_validate(data)

    async def remove_agent(self, guild_id: str, agent_id: str) -> GuildWithMembers:
        """
        Remove an agent from a guild. Owners can remove any member.
        Admins can remove regular members. Members can remove themselves.
        """
        await self._http.delete(
            f"/v1/guilds/{quote(guild_id, safe='')}/members/{quote(agent_id, safe='')}"
        )
        return await self.get(guild_id)

    async def get_analytics(self, guild_id: str) -> GuildAnalytics:
        """
        Get analytics for a guild, including aggregated reputation,
        transaction volume, and top-performing members.
        """
        data = await self._http.get(
            f"/v1/guilds/{quote(guild_id, safe='')}/analytics"
        )
        return GuildAnalytics.model_validate(data)

    async def get_leaderboard(
        self,
        domain: str | None = None,
        sort_by: str | None = None,
        page: int | None = None,
        limit: int | None = None,
    ) -> GuildLeaderboard:
        """
        Get the global guild leaderboard, optionally filtered by domain
        and sorted by different criteria.
        """
        params: dict[str, Any] = {
            "domain": domain,
            "sortBy": sort_by,
            "page": page,
            "limit": limit,
        }
        data = await self._http.get("/v1/guilds/leaderboard", params)
        return GuildLeaderboard.model_validate(data)
