"""
Organization group CRUD operations
"""

from typing import Dict, Any, List, Optional
from ..models import Group, TallyfyError
from ..validation import validate_id


class GroupManager:
    """Handles organization group CRUD operations"""

    def __init__(self, sdk):
        self.sdk = sdk

    def _validate_org_id(self, org_id: str) -> None:
        validate_id(org_id, "org_id")

    def _validate_group_id(self, group_id: str) -> None:
        validate_id(group_id, "group_id")

    def _handle_api_error(self, error: Exception, operation: str, **context) -> None:
        context_str = ", ".join(f"{k}={v}" for k, v in context.items())
        msg = f"Failed to {operation}"
        if context_str:
            msg += f" ({context_str})"
        msg += f": {error}"
        self.sdk.logger.error(msg)
        if isinstance(error, TallyfyError):
            raise error
        raise TallyfyError(msg)

    def _parse_group(self, response_data: Any) -> Group:
        """Extract a Group from a wrapped or bare API response."""
        if isinstance(response_data, dict) and 'data' in response_data:
            data = response_data['data']
            if isinstance(data, dict):
                return Group.from_dict(data)
        if isinstance(response_data, dict):
            return Group.from_dict(response_data)
        raise TallyfyError("Unexpected response format")

    # ── READ ──────────────────────────────────────────────────────────────

    def get_groups(self, org_id: str, page: int = 1, per_page: int = 100,
                   q: Optional[str] = None, sort_by: Optional[str] = None,
                   sort: Optional[str] = None, with_data: Optional[str] = None) -> List[Group]:
        """
        List all groups in the organization.

        Args:
            org_id: Organization ID
            page: Page number (default: 1)
            per_page: Results per page (default: 100)
            q: Search query
            sort_by: Sort field
            sort: Sort direction
            with_data: Additional relations to include

        Returns:
            List of Group objects

        Raises:
            TallyfyError: If the request fails
        """
        self._validate_org_id(org_id)

        try:
            endpoint = f"organizations/{org_id}/groups"
            params: Dict[str, Any] = {"page": page, "per_page": per_page}
            if q is not None:
                params["q"] = q
            if sort_by is not None:
                params["sort_by"] = sort_by
            if sort is not None:
                params["sort"] = sort
            if with_data is not None:
                params["with"] = with_data

            response_data = self.sdk._make_request('GET', endpoint, params=params)

            if isinstance(response_data, dict) and 'data' in response_data:
                items = response_data['data']
            elif isinstance(response_data, list):
                items = response_data
            else:
                items = []

            return [Group.from_dict(item) for item in items if isinstance(item, dict)]

        except TallyfyError:
            raise
        except Exception as e:
            self._handle_api_error(e, "get groups", org_id=org_id)

    def get_group(self, org_id: str, group_id: str,
                  with_data: Optional[str] = None) -> Group:
        """
        Get a single group by ID.

        Args:
            org_id: Organization ID
            group_id: Group ID
            with_data: Additional relations to include

        Returns:
            Group object

        Raises:
            TallyfyError: If the request fails
        """
        self._validate_org_id(org_id)
        self._validate_group_id(group_id)

        try:
            endpoint = f"organizations/{org_id}/groups/{group_id}"
            params = {"with": with_data} if with_data else None
            response_data = self.sdk._make_request('GET', endpoint, params=params)
            return self._parse_group(response_data)

        except TallyfyError:
            raise
        except Exception as e:
            self._handle_api_error(e, "get group", org_id=org_id, group_id=group_id)

    # ── CREATE ────────────────────────────────────────────────────────────

    def create_group(self, org_id: str, name: str,
                     description: Optional[str] = None,
                     members: Optional[List[int]] = None,
                     guests: Optional[List[str]] = None) -> Group:
        """
        Create a new group in the organization.

        Args:
            org_id: Organization ID
            name: Group name (required)
            description: Optional group description
            members: List of member user IDs to add
            guests: List of guest email addresses to add

        Returns:
            Created Group object

        Raises:
            TallyfyError: If the request fails
            ValueError: If required parameters are missing
        """
        self._validate_org_id(org_id)

        if not name or not isinstance(name, str):
            raise ValueError("name must be a non-empty string")

        try:
            endpoint = f"organizations/{org_id}/groups"
            body: Dict[str, Any] = {"name": name}
            if description:
                body["description"] = description
            if members:
                body["members"] = members
            if guests:
                body["guests"] = guests

            response_data = self.sdk._make_request('POST', endpoint, data=body)
            return self._parse_group(response_data)

        except TallyfyError:
            raise
        except Exception as e:
            self._handle_api_error(e, "create group", org_id=org_id, name=name)

    # ── UPDATE ────────────────────────────────────────────────────────────

    def update_group(self, org_id: str, group_id: str,
                     name: Optional[str] = None,
                     description: Optional[str] = None,
                     members: Optional[List[int]] = None,
                     guests: Optional[List[str]] = None) -> Group:
        """
        Update a group's properties.

        Args:
            org_id: Organization ID
            group_id: Group ID to update
            name: New group name
            description: New group description
            members: New list of member user IDs (replaces existing)
            guests: New list of guest email addresses (replaces existing)

        Returns:
            Updated Group object

        Raises:
            TallyfyError: If the request fails
            ValueError: If required parameters are missing
        """
        self._validate_org_id(org_id)
        self._validate_group_id(group_id)

        try:
            endpoint = f"organizations/{org_id}/groups/{group_id}"

            # The PUT endpoint requires all fields; fetch current state and merge.
            current = self.get_group(org_id, group_id)
            body: Dict[str, Any] = {
                "name": name if name is not None else current.name,
                "description": description if description is not None else (current.description or ""),
                "members": members if members is not None else (current.members or []),
                "guests": guests if guests is not None else (current.guests or []),
            }

            response_data = self.sdk._make_request('PUT', endpoint, data=body)
            return self._parse_group(response_data)

        except TallyfyError:
            raise
        except Exception as e:
            self._handle_api_error(e, "update group", org_id=org_id, group_id=group_id)

    # ── DELETE ────────────────────────────────────────────────────────────

    def delete_group(self, org_id: str, group_id: str) -> bool:
        """
        Delete a group.

        Args:
            org_id: Organization ID
            group_id: Group ID to delete

        Returns:
            True if deleted successfully

        Raises:
            TallyfyError: If the request fails
            ValueError: If required parameters are missing
        """
        self._validate_org_id(org_id)
        self._validate_group_id(group_id)

        try:
            endpoint = f"organizations/{org_id}/groups/{group_id}"
            self.sdk._make_request('DELETE', endpoint)
            return True

        except TallyfyError:
            raise
        except Exception as e:
            self._handle_api_error(e, "delete group", org_id=org_id, group_id=group_id)
