"""IAM access management utilities for GCP."""

import logging
import google.cloud.logging
from google.cloud import asset_v1, resourcemanager_v3
from typing import Optional

# Initialize Google Cloud Logging
client = google.cloud.logging.Client()
client.setup_logging()

# Configure the logger
logger = logging.getLogger("uvicorn")
logger.setLevel(logging.INFO)


def _get_identity_string(email: str) -> str:
    """
    Helper function to construct the proper identity string.
    Automatically detects if the email is a service account or user.
    
    Args:
        email: Email address (user or service account)
        
    Returns:
        str: Properly formatted identity string
    """
    if ".gserviceaccount.com" in email.lower():
        return f"serviceAccount:{email}"
    else:
        return f"user:{email}"


def check_user_has_role_in_project(
    project_id: str,
    user_email: str,
    organization_id: str,
    role: str = "roles/owner",
    expand_groups: bool = True
) -> bool:
    """
    Check if a user or service account has a specific role in a GCP project.
    
    Args:
        user_email: Email of the user or service account to check
                   (e.g., 'oshasha10@dev.sky320.com' or 'my-sa@project.iam.gserviceaccount.com')
        role: Role to check (e.g., 'roles/owner', 'roles/editor')
        project_id: GCP project ID (e.g., 'sky-starfi-mam-res-gcpro-1')
        organization_id: GCP organization ID (e.g., '111111111111')
        expand_groups: Whether to expand group memberships (default: True)
        
    Returns:
        bool: True if the user/service account has the role in the project, False otherwise
        
    Example:
        >>> has_access = check_user_has_role_in_project(
        ...     user_email='oshasha10@dev.sky320.com',
        ...     role='roles/owner',
        ...     project_id='sky-starfi-mam-res-gcpro-1',
        ... )
    """
    client = asset_v1.AssetServiceClient()
    
    # Construct the full resource name
    scope = f"organizations/{organization_id}"
    full_resource_name = f"//cloudresourcemanager.googleapis.com/projects/{project_id}"
    identity = _get_identity_string(user_email)
    
    # Build the request
    request = asset_v1.AnalyzeIamPolicyRequest(
        analysis_query=asset_v1.IamPolicyAnalysisQuery(
            scope=scope,
            resource_selector=asset_v1.IamPolicyAnalysisQuery.ResourceSelector(
                full_resource_name=full_resource_name
            ),
            identity_selector=asset_v1.IamPolicyAnalysisQuery.IdentitySelector(
                identity=identity
            ),
            access_selector=asset_v1.IamPolicyAnalysisQuery.AccessSelector(
                roles=[role]
            ),
            options=asset_v1.IamPolicyAnalysisQuery.Options(
                expand_groups=expand_groups,
                expand_roles=True,
                # expand_resources=True
            )
        )
    )
    
    try:
        # Execute the analysis
        logger.info(f"Checking if {user_email} has role {role} in project {project_id}")
        response = client.analyze_iam_policy(request=request)
        
        # Check if any results were returned
        # If the user has the role, there will be analysis results
        if response.main_analysis and response.main_analysis.analysis_results:
            logger.info(f"{user_email} has role {role} in project {project_id}")
            return True
        
        logger.info(f"{user_email} does not have role {role} in project {project_id}")
        return False
        
    except Exception as e:
        logger.exception(f"Error analyzing IAM policy: {e}")
        raise


def _get_all_folders_recursive(parent: str, folders_client) -> list:
    """
    Recursively get all folders under a parent (organization or folder).
    
    Args:
        parent: Parent resource (e.g., 'organizations/123' or 'folders/456')
        folders_client: FoldersClient instance
        
    Returns:
        list: List of all folder resource names
    """
    all_folders = []
    
    try:
        request = resourcemanager_v3.ListFoldersRequest(parent=parent)
        folders = folders_client.list_folders(request=request)
        
        for folder in folders:
            folder_name = folder.name  # Format: folders/123
            all_folders.append(folder_name)
            logger.info(f"Found folder: {folder_name}")
            
            # Recursively get subfolders
            subfolders = _get_all_folders_recursive(folder_name, folders_client)
            all_folders.extend(subfolders)
            
    except Exception as e:
        logger.warning(f"Error listing folders under {parent}: {e}")
    
    return all_folders


def get_projects_with_role(
    user_email: str,
    organization_id: str,
    role: str = "roles/owner",
    expand_groups: bool = True
) -> list:
    """
    Get all projects where a user or service account has a specific role.
    Searches recursively through all folders in the organization.
    
    Args:
        user_email: Email of the user or service account to check
                   (e.g., 'oshasha10@dev.sky320.com' or 'my-sa@project.iam.gserviceaccount.com')
        organization_id: GCP organization ID (e.g., '111111111111')
        role: Role to check (e.g., 'roles/owner', 'roles/editor')
        expand_groups: Whether to expand group memberships (default: True)
        
    Returns:
        list: List of project IDs where the user/service account has the specified role
        
    Example:
        >>> projects = get_projects_with_role(
        ...     user_email='oshasha10@dev.sky320.com',
        ...     organization_id='111111111111',
        ...     role='roles/owner'
        ... )
    """
    logger.info(f"Fetching all projects in organization {organization_id} (including folders)")
    
    try:
        # Initialize clients
        projects_client = resourcemanager_v3.ProjectsClient()
        folders_client = resourcemanager_v3.FoldersClient()
        
        # Get all folders recursively
        org_parent = f"organizations/{organization_id}"
        all_folders = _get_all_folders_recursive(org_parent, folders_client)
        logger.info(f"Found {len(all_folders)} folder(s) in organization")
        
        # Create list of all parents to search (organization + all folders)
        parents_to_search = [org_parent] + all_folders
        
        # Collect all projects from all parents
        all_projects = []
        for parent in parents_to_search:
            request = resourcemanager_v3.ListProjectsRequest(parent=parent)
            projects = projects_client.list_projects(request=request)
            for project in projects:
                all_projects.append(project.project_id)
        
        logger.info(f"Found {len(all_projects)} total project(s) across organization and folders")
        
        # Filter projects where user has the specified role
        matching_projects = []
        
        for project_id in all_projects:
            # Check if user has the role in this project
            if check_user_has_role_in_project(
                project_id=project_id,
                user_email=user_email,
                organization_id=organization_id,
                role=role,
                expand_groups=expand_groups
            ):
                matching_projects.append(project_id)
        
        logger.info(f"Checked {len(all_projects)} projects, found {len(matching_projects)} where {user_email} has role {role}")
        return sorted(matching_projects)
        
    except Exception as e:
        logger.exception(f"Error fetching projects: {e}")
        raise
