import os
from typing import Dict, Optional, Any, TypedDict, List
from supabase import create_client, Client
from supabase.lib.client_options import SyncClientOptions
from supabase_auth import SyncMemoryStorage
from modules.logger_tool import initialise_logger

logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)

class CreateBucketOptions(TypedDict, total=False):
    """Options for bucket creation, matching Supabase API requirements"""
    public: bool
    file_size_limit: int
    allowed_mime_types: List[str]
    name: str

def _create_base_client(url: str, key: str, access_token: Optional[str] = None, options: Optional[Dict[str, Any]] = None) -> Client:
    """Create a base Supabase client with given configuration.
    
    If access_token is provided, it is used as the Authorization header (for per-user RLS).
    Otherwise, the API key is used (service role bypasses RLS, anon key does not).
    """
    # If an access token is provided, use it for Authorization (enables per-user RLS)
    # Otherwise fall back to the API key
    auth_header = f"Bearer {access_token}" if access_token else f"Bearer {key}"

    # Only override Authorization here. apikey is supplied to create_client via the `key` arg and
    # set by supabase-py itself; setting it again here sends a DUPLICATE apikey header that the
    # Supabase gateway (Kong) rejects with 401 "Duplicate API key found". For a per-user client
    # apikey stays the anon key (from `key`) while this Authorization carries the user JWT.
    headers = {
        "Authorization": auth_header,
    }
    if options:
        headers.update(options.get("headers", {}))

    client_options = SyncClientOptions(
        schema="public",
        storage=SyncMemoryStorage(),
        headers=headers,
    )
    return create_client(url, key, options=client_options)

class SupabaseServiceRoleClient:
    """Supabase client for making authenticated requests using the service role key.
    
    NOTE: Service role bypasses all RLS policies. Use only for admin operations
    where you need to read/write any row regardless of ownership.
    """
    
    def __init__(self, url: Optional[str] = None, service_role_key: Optional[str] = None):
        """Initialize the Supabase client with URL and service role key"""
        self.url = url or os.environ.get("SUPABASE_URL", "http://localhost:8000")
        self.service_role_key = service_role_key or os.environ.get("SERVICE_ROLE_KEY")
        
        if not self.url or not self.service_role_key:
            raise ValueError("SUPABASE_URL and SERVICE_ROLE_KEY must be provided")
        
        # Initialize Supabase client with service role key (bypasses RLS)
        self.supabase = _create_base_client(self.url, self.service_role_key)

    def create_bucket(self, id: str, options: Optional[CreateBucketOptions] = None) -> Dict[str, Any]:
        """Create a storage bucket with the given ID and options"""
        if options is None:
            options = CreateBucketOptions()
        if 'name' not in options:
            options['name'] = id  # Use ID as default name if not provided
        return self.supabase.storage.create_bucket(id, options=options)

class SupabaseAnonClient:
    """Supabase client for making authenticated requests using the anon key.
    
    When initialized with an access_token, per-user RLS policies are enforced
    via auth.uid() in the JWT. Without an access_token, requests use the anon key
    which does NOT enforce per-user RLS (only bucket-level storage rules apply).
    """
    
    def __init__(self, url: Optional[str] = None, anon_key: Optional[str] = None, access_token: Optional[str] = None):
        """Initialize the Supabase client with URL and anon key.
        
        Args:
            url: Supabase URL
            anon_key: Anon API key (fallback if no access_token)
            access_token: User's JWT access token for per-user RLS enforcement
        """
        self.url = url or os.environ.get("SUPABASE_URL", "http://localhost:8000")
        self.anon_key = anon_key or os.environ.get("ANON_KEY")
        self.access_token = access_token
        
        if not self.url or not self.anon_key:
            raise ValueError("SUPABASE_URL and ANON_KEY must be provided")
        
        # Initialize Supabase client with anon key and optional access token for RLS
        self.supabase = _create_base_client(self.url, self.anon_key, access_token=access_token)

    def create_bucket(self, id: str, options: Optional[CreateBucketOptions] = None) -> Dict[str, Any]:
        """Create a storage bucket with the given ID and options"""
        return self.supabase.storage.create_bucket(id, options=options)

    @classmethod
    def for_user(cls, access_token: str) -> 'SupabaseAnonClient':
        """Create a client instance for a specific user using their access token.
        
        This enables per-user RLS enforcement via auth.uid() in the JWT.
        """
        if not access_token or not access_token.strip():
            raise ValueError("access_token is required for per-user Supabase clients")
        token = access_token.strip()
        if token.lower().startswith("bearer "):
            token = token.split(None, 1)[1]
        return cls(access_token=token)
