"""
Authorization schemas from rbac.yaml.

These schemas provide type-safe access to document access levels
and the permission matrix defined in rbac.yaml.

SST File: lightwave/schema/definitions/rbac.yaml
Database Model: None (config-driven, not DB-backed)

Usage:
    from lightwave.schema.pydantic.models.authorization import (
        DocumentAccessLevel,
        PermissionMatrixEntry,
        AuthorizationConfig,
    )

    # Load all authorization config
    config = AuthorizationConfig.get_from_sst()

    # Check document access level permissions
    owner_level = config.document_access_levels["owner"]
    print(owner_level.permissions)  # ["view", "edit", "delete", "share", ...]

    # Check permission matrix
    page_perms = config.get_permissions_for_resource("page", "tenant_admin")
    print(page_perms)  # ["view", "create", "edit", "delete", "publish", ...]
"""

from pathlib import Path
from typing import Any, ClassVar, Literal

import yaml
from pydantic import Field

from lightwave.schema.pydantic.core.base import SSTSchema

# =============================================================================
# User Role Types
# =============================================================================

UserRoleType = Literal[
    "platform_admin",
    "tenant_admin",
    "tenant_creator",
    "tenant_subscriber",
    "team_owner",
    "team_member",
    "team_viewer",
    "customer",
    "newsletter_subscriber",
    "guest",
    "system",
]

DocumentAccessLevelType = Literal[
    "owner",
    "editor",
    "commenter",
    "viewer",
    "public",
]

ResourceType = Literal[
    "page",
    "site",
    "team",
    "user",
    "api_key",
    "billing",
    "production",
    "call_sheet",
    "shot_list",
    "file",
]

PermissionType = Literal[
    "view",
    "create",
    "edit",
    "delete",
    "publish",
    "unpublish",
    "approve",
    "manage",
    "configure",
    "invite",
    "remove",
    "assign_roles",
    "revoke",
    "propose",
    "export",
    "distribute",
    "upload",
    "share",
    "comment",
    "manage_permissions",
]


# =============================================================================
# Document Access Level Schema
# =============================================================================


class DocumentAccessLevel(SSTSchema):
    """
    Document-level access control definition.

    Defines what permissions a specific access level grants
    for document sharing and collaboration.

    Example:
        {
            "name": "Editor",
            "description": "Can view and modify content",
            "permissions": ["view", "edit", "comment"],
            "can_share": false
        }
    """

    name: str = Field(..., description="Display name of access level")
    description: str = Field(..., description="Human-readable description")
    permissions: list[str] = Field(
        default_factory=list,
        description="Permissions granted at this level",
    )
    can_transfer: bool = Field(False, description="Whether ownership can be transferred")
    can_share: bool = Field(True, description="Whether document can be shared at this level")
    can_export: bool = Field(True, description="Whether document can be exported")
    requires_auth: bool = Field(True, description="Whether authentication is required")
    track_views: bool = Field(False, description="Whether to track view analytics")
    notes: str | None = Field(None, description="Additional notes")

    def has_permission(self, permission: str) -> bool:
        """Check if this access level grants a specific permission."""
        return permission in self.permissions


# =============================================================================
# Permission Matrix Entry Schema
# =============================================================================


class PermissionMatrixEntry(SSTSchema):
    """
    Single entry in the permission matrix.

    Maps a (resource_type, role) pair to a list of permissions.

    Example:
        {
            "resource_type": "page",
            "role": "tenant_admin",
            "permissions": ["view", "create", "edit", "delete", "publish"]
        }
    """

    resource_type: str = Field(..., description="Resource type (page, site, team, etc.)")
    role: str = Field(..., description="User role (platform_admin, tenant_admin, etc.)")
    permissions: list[str] = Field(
        default_factory=list,
        description="Permissions granted for this resource/role combination",
    )

    def has_permission(self, permission: str) -> bool:
        """Check if this entry grants a specific permission."""
        return permission in self.permissions


# =============================================================================
# Authorization Config Schema
# =============================================================================


class AuthorizationConfig(SSTSchema):
    """
    Complete authorization configuration from rbac.yaml.

    Provides access to document access levels and permission matrix.

    Example:
        config = AuthorizationConfig.get_from_sst()

        # Get document access level
        editor = config.document_access_levels["editor"]
        print(editor.permissions)

        # Check permission matrix
        if config.can_perform("page", "tenant_admin", "publish"):
            print("Can publish pages")
    """

    SST_KEY: ClassVar[str] = "rbac"  # Registry key in __index.yaml

    document_access_levels: dict[str, DocumentAccessLevel] = Field(
        default_factory=dict,
        description="Document access level definitions",
    )
    permission_matrix: dict[str, dict[str, list[str]]] = Field(
        default_factory=dict,
        description="Resource -> Role -> Permissions mapping",
    )
    user_roles: list[str] = Field(
        default_factory=list,
        description="All defined user roles",
    )

    @classmethod
    def get_sst_path(cls) -> Path:
        """Get path to SST YAML file (from __index.yaml registry)."""
        from lightwave.schema.core.paths import get_sst_path

        return get_sst_path(cls.SST_KEY)

    @classmethod
    def load_sst_data(cls) -> dict[str, Any]:
        """Load SST YAML file."""
        sst_path = cls.get_sst_path()
        if not sst_path.exists():
            raise FileNotFoundError(f"SST file not found: {sst_path}")
        with open(sst_path) as f:
            return yaml.safe_load(f)

    @classmethod
    def get_from_sst(cls) -> "AuthorizationConfig":
        """
        Load authorization configuration from SST YAML.

        Returns:
            AuthorizationConfig instance with access levels and permission matrix
        """
        data = cls.load_sst_data()

        # Parse document access levels
        access_levels_raw = data.get("document_access_levels", {})
        document_access_levels = {}
        for level_name, level_data in access_levels_raw.items():
            document_access_levels[level_name] = DocumentAccessLevel(**level_data)

        # Parse permission matrix (already in correct structure)
        permission_matrix = data.get("permission_matrix", {})

        # Get user roles
        user_roles = list(data.get("user_roles", {}).keys())

        return cls(
            document_access_levels=document_access_levels,
            permission_matrix=permission_matrix,
            user_roles=user_roles,
        )

    def get_access_level(self, level: str) -> DocumentAccessLevel | None:
        """
        Get a document access level by name.

        Args:
            level: Access level name (owner, editor, viewer, etc.)

        Returns:
            DocumentAccessLevel or None if not found
        """
        return self.document_access_levels.get(level)

    def get_permissions_for_resource(self, resource_type: str, role: str) -> list[str]:
        """
        Get permissions for a resource/role combination.

        Args:
            resource_type: Resource type (page, site, team, etc.)
            role: User role (platform_admin, tenant_admin, etc.)

        Returns:
            List of permissions (empty if not found)
        """
        resource_perms = self.permission_matrix.get(resource_type, {})
        return resource_perms.get(role, [])

    def can_perform(self, resource_type: str, role: str, permission: str) -> bool:
        """
        Check if a role can perform an action on a resource.

        Args:
            resource_type: Resource type (page, site, team, etc.)
            role: User role (platform_admin, tenant_admin, etc.)
            permission: Permission to check (view, edit, delete, etc.)

        Returns:
            True if permission is granted

        Example:
            if config.can_perform("page", "tenant_admin", "publish"):
                # Allow publishing
        """
        permissions = self.get_permissions_for_resource(resource_type, role)
        return permission in permissions

    def get_all_permissions_for_role(self, role: str) -> dict[str, list[str]]:
        """
        Get all permissions for a role across all resources.

        Args:
            role: User role to query

        Returns:
            Dict mapping resource_type to list of permissions
        """
        result: dict[str, list[str]] = {}
        for resource_type, role_perms in self.permission_matrix.items():
            if role in role_perms:
                result[resource_type] = role_perms[role]
        return result

    def get_roles_with_permission(self, resource_type: str, permission: str) -> list[str]:
        """
        Get all roles that have a specific permission on a resource.

        Args:
            resource_type: Resource type to check
            permission: Permission to look for

        Returns:
            List of roles with the permission
        """
        roles: list[str] = []
        resource_perms = self.permission_matrix.get(resource_type, {})
        for role, perms in resource_perms.items():
            if permission in perms:
                roles.append(role)
        return roles

    def get_permission_matrix_entries(self) -> list[PermissionMatrixEntry]:
        """
        Get all permission matrix entries as structured objects.

        Returns:
            List of PermissionMatrixEntry objects
        """
        entries: list[PermissionMatrixEntry] = []
        for resource_type, role_perms in self.permission_matrix.items():
            for role, permissions in role_perms.items():
                entries.append(
                    PermissionMatrixEntry(
                        resource_type=resource_type,
                        role=role,
                        permissions=permissions,
                    )
                )
        return entries
