"""
Tenant-level settings and configurations for Microsoft Fabric.

Provides access to tenant-wide settings and administrative operations.

Requires: Fabric Administrator permissions
"""

from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union

import requests as _requests

if TYPE_CHECKING:
    from datetime import datetime

    from .._client import FabricClient


class ActivityEvent:
    """
    Represents a single Power BI / Fabric activity event.

    Raw event data is available via the ``_data`` attribute for fields
    not surfaced as properties.

    Examples:
        >>> events = fabric.tenant().activityEvents(
        ...     start="2024-01-01T00:00:00",
        ...     end="2024-01-01T23:59:59"
        ... )
        >>> for evt in events:
        ...     print(f"{evt.creation_time}: {evt.operation} by {evt.user_id}")
    """

    def __init__(self, data: Dict[str, Any]):
        self._data = data
        self.id: Optional[str] = data.get("Id")
        self.creation_time: Optional[str] = data.get("CreationTime")
        self.record_type: Optional[int] = data.get("RecordType")
        self.operation: Optional[str] = data.get("Operation")
        self.activity: Optional[str] = data.get("Activity")
        self.user_id: Optional[str] = data.get("UserId")
        self.workspace_id: Optional[str] = data.get("WorkSpaceId")
        self.workspace_name: Optional[str] = data.get("WorkspaceName")
        self.item_id: Optional[str] = data.get("ArtifactId")
        self.item_name: Optional[str] = data.get("ArtifactName")
        self.item_kind: Optional[str] = data.get("ArtifactKind")

    def __repr__(self) -> str:
        return f"ActivityEvent(op={self.operation!r}, user={self.user_id!r}, time={self.creation_time!r})"


class TenantSetting:
    """
    Represents a single tenant setting.

    Attributes:
        setting_name (str): Unique setting identifier
        title (str): Display title
        enabled (bool): Whether setting is enabled
        tenant_setting_group (str): Category/group name
        can_specify_security_groups (bool): Whether setting can be scoped to groups
        enabled_security_groups (list): Security groups with this setting enabled
        excluded_security_groups (list): Security groups excluded from this setting
    """

    def __init__(self, client: "FabricClient", data: Dict[str, Any]):
        """
        Initialize TenantSetting from API response.

        Args:
            client: Authenticated FabricClient
            data: Setting data from API
        """
        self._client = client
        self._data = data

        self.setting_name = data.get("settingName")
        self.title = data.get("title")
        self.enabled = data.get("enabled", False)
        self.tenant_setting_group = data.get("tenantSettingGroup")
        self.can_specify_security_groups = data.get("canSpecifySecurityGroups", False)
        self.enabled_security_groups = data.get("enabledSecurityGroups", [])
        self.excluded_security_groups = data.get("excludedSecurityGroups", [])
        self.properties = data.get("properties", [])

    def __repr__(self) -> str:
        return f"TenantSetting(name={self.setting_name}, enabled={self.enabled})"


class Tenant:
    """
    Represents the Fabric tenant and provides access to tenant-level settings.

    This is a singleton-style class - there's only one tenant per authentication context.

    Examples:
        >>> tenant = fabric.tenant
        >>>
        >>> # List all settings
        >>> for setting in tenant.settings():
        ...     print(f"{setting.title}: {setting.enabled}")
        >>>
        >>> # Get specific setting
        >>> setting = tenant.setting("AdminApisIncludeDetailedMetadata")
        >>> print(f"Enabled: {setting.enabled}")
    """

    def __init__(self, client: "FabricClient"):
        """
        Initialize Tenant.

        Args:
            client: Authenticated FabricClient
        """
        self._client = client

    def settings(self) -> List[TenantSetting]:
        """
        List all tenant settings.

        Automatically handles pagination via continuation tokens.

        Returns:
            list[TenantSetting]: All tenant settings

        Examples:
            >>> tenant = fabric.tenant
            >>> settings = tenant.settings()
            >>>
            >>> # Filter by group
            >>> export_settings = [
            ...     s for s in settings
            ...     if s.tenant_setting_group == "ExportAndSharing"
            ... ]
        """
        # Get all tenant settings (pagination handled automatically by client)
        endpoint = "/admin/tenantsettings"
        response = self._client.get(endpoint)
        data = response.json()

        return [TenantSetting(self._client, setting_data) for setting_data in data.get("value", [])]

    def setting(self, setting_name: str) -> Optional[TenantSetting]:
        """
        Get a specific tenant setting by name.

        Args:
            setting_name: Setting identifier (e.g., "AdminApisIncludeDetailedMetadata")

        Returns:
            TenantSetting: The setting, or None if not found

        Examples:
            >>> tenant = fabric.tenant
            >>> setting = tenant.setting("DatamartTenant")
            >>> if setting:
            ...     print(f"Enabled: {setting.enabled}")
        """
        # Note: API doesn't have single-setting endpoint, so we list and filter
        settings = self.settings()
        matches = [s for s in settings if s.setting_name == setting_name]
        return matches[0] if matches else None

    def updateSetting(
        self,
        setting_name: str,
        enabled: bool,
        enabled_security_groups: Optional[List[str]] = None,
        excluded_security_groups: Optional[List[str]] = None,
    ) -> None:
        """
        Update a tenant setting.

        Args:
            setting_name: Setting identifier
            enabled: Enable or disable the setting
            enabled_security_groups: Optional list of security group IDs to enable for
            excluded_security_groups: Optional list of security group IDs to exclude

        Examples:
            >>> tenant = fabric.tenant
            >>> tenant.updateSetting(
            ...     "DatamartTenant",
            ...     enabled=True,
            ...     enabled_security_groups=["group-guid-1", "group-guid-2"]
            ... )

        Note:
            This operation requires Fabric Administrator permissions and may
            require PIM (Privileged Identity Management) elevation.
        """
        payload = {"settingName": setting_name, "enabled": enabled}

        if enabled_security_groups is not None:
            payload["enabledSecurityGroups"] = [
                {"graphId": group_id} for group_id in enabled_security_groups
            ]

        if excluded_security_groups is not None:
            payload["excludedSecurityGroups"] = [
                {"graphId": group_id} for group_id in excluded_security_groups
            ]

        self._client.patch("/admin/tenantsettings", data=payload)

    def activityEvents(
        self,
        start: "Union[str, datetime]",
        end: "Union[str, datetime]",
        filter: Optional[str] = None,
    ) -> List[ActivityEvent]:
        """
        Get Power BI / Fabric activity events for a time range.

        Calls ``GET https://api.powerbi.com/v1.0/myorg/admin/activityevents``
        and returns all events, automatically following continuation pages.

        Args:
            start: Start of time range — ``datetime`` or ISO 8601 string
                   (e.g., ``'2024-06-01T00:00:00'``).
            end: End of time range — ``datetime`` or ISO 8601 string
                 (e.g., ``'2024-06-01T23:59:59'``).
            filter: Optional OData filter to narrow results
                    (e.g., ``"Activity eq 'ShareReport'"``).

        Returns:
            list[ActivityEvent]: All matching activity events.

        Note:
            Requires **Tenant.Read.All** (or **Tenant.ReadWrite.All**) permission
            and the Power BI service principal scope
            ``https://analysis.windows.net/powerbi/api/.default``.
        """
        from datetime import datetime as _dt

        from .._client import FabricClient

        POWERBI_SCOPE = FabricClient.POWERBI_SCOPE

        def _fmt(v: Any) -> str:
            if isinstance(v, _dt):
                v = v.strftime("%Y-%m-%dT%H:%M:%S")
            return f"'{str(v).strip(chr(39))}'"

        params: Dict[str, str] = {"startDateTime": _fmt(start), "endDateTime": _fmt(end)}
        if filter:
            params["$filter"] = filter

        url: Optional[str] = "https://api.powerbi.com/v1.0/myorg/admin/activityevents"

        # Build headers using the Power BI scope (different from Fabric scope)
        headers = self._client._default_headers.copy()
        headers["Authorization"] = self._client._auth.getAuthorizationHeader(POWERBI_SCOPE)

        all_events: List[ActivityEvent] = []

        params_or_none: Optional[Dict[str, str]] = params

        while url:
            response = _requests.get(url, headers=headers, params=params_or_none)
            self._client._handle_response(response)  # Raise ApiError / AuthError on failure
            data = response.json()

            all_events.extend(ActivityEvent(e) for e in data.get("activityEventEntities", []))

            # continuationUri already encodes all query params for subsequent pages
            params_or_none = None
            url = None if data.get("lastResultSet", True) else data.get("continuationUri")

        return all_events

    def __repr__(self) -> str:
        return "Tenant(admin)"
