"""
TLDraw Supabase Storage Router
=============================

Handles TLDraw snapshot operations using Supabase Storage instead of local filesystem.
This replaces the old filesystem-based tldraw_filesystem.py router.
"""

from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
import os
import json
import logging
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import Dict, Any, Tuple

from modules.auth.supabase_bearer import SupabaseBearer
from modules.database.supabase.utils.client import SupabaseServiceRoleClient
from modules.database.supabase.utils.storage import StorageError, StorageUser
from modules.logger_tool import initialise_logger

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

ALLOWED_SNAPSHOT_BUCKETS = {"cc.public.snapshots"}
PERSONAL_NODE_TYPES = {"User", "Teacher", "Developer", "SuperAdmin", "UserTeacherTimetable"}
GLOBAL_READONLY_NODE_TYPES = {"CalendarYear", "CalendarMonth", "CalendarWeek", "CalendarDay", "CalendarTimeChunk"}


def _sb() -> SupabaseServiceRoleClient:
    return SupabaseServiceRoleClient()


def _parse_snapshot_path(path: str) -> Tuple[str, str, str, str]:
    """Parse and validate bucket/node_type/node_id into a storage object path."""
    if not path:
        raise HTTPException(status_code=400, detail="Path not provided")
    path_parts = [part for part in path.split('/') if part]
    if len(path_parts) != 3:
        raise HTTPException(status_code=400, detail="Invalid path format. Expected: bucket/nodetype/node_id")

    bucket, node_type, node_id = path_parts
    if bucket not in ALLOWED_SNAPSHOT_BUCKETS:
        raise HTTPException(status_code=403, detail="Snapshot bucket is not allowed")
    if any(part in {".", ".."} or ".." in part for part in path_parts):
        raise HTTPException(status_code=400, detail="Invalid path component")
    if not node_type.replace("_", "").replace("-", "").isalnum():
        raise HTTPException(status_code=400, detail="Invalid node type")
    if not node_id.replace("_", "").replace("-", "").isalnum():
        raise HTTPException(status_code=400, detail="Invalid node id")

    return bucket, node_type, node_id, f"{node_type}/{node_id}/tldraw_file.json"


def _user_scope(user_id: str) -> Dict[str, Any]:
    """Resolve Supabase/Neo4j scope for the authenticated user."""
    scope: Dict[str, Any] = {
        "user_id": user_id,
        "teacher_db": f"cc.users.teacher.{user_id.replace('-', '')}" if user_id else "",
        "institute_id": "",
        "institute_db": "",
        "curriculum_db": "",
    }
    if not user_id:
        return scope
    try:
        sb = _sb()
        prof = sb.supabase.table("profiles").select("school_id").eq("id", user_id).single().execute()
        school_id = str((prof.data or {}).get("school_id") or "")
        scope["institute_id"] = school_id
        if school_id:
            inst = sb.supabase.table("institutes").select("neo4j_uuid_string").eq("id", school_id).single().execute()
            neo4j_uuid = (inst.data or {}).get("neo4j_uuid_string")
            if neo4j_uuid:
                scope["institute_db"] = f"cc.institutes.{neo4j_uuid}"
                scope["curriculum_db"] = f"cc.institutes.{neo4j_uuid}.curriculum"
    except Exception as exc:
        logger.warning(f"Could not resolve TLDraw storage scope for user {user_id}: {exc}")
    return scope


def _authorize_snapshot_path(path: str, db_name: str, credentials: Dict[str, Any], write: bool) -> Tuple[str, str, str, str]:
    """Authorize TLDraw snapshot access before touching Supabase Storage."""
    user_id = credentials.get("sub", "")
    if not user_id:
        raise HTTPException(status_code=403, detail="Could not extract user_id from token")
    bucket, node_type, node_id, file_path = _parse_snapshot_path(path)
    scope = _user_scope(user_id)
    allowed_dbs = {db for db in (scope["teacher_db"], scope["institute_db"], scope["curriculum_db"]) if db}

    if node_type in PERSONAL_NODE_TYPES:
        if node_id == user_id or (db_name and db_name == scope["teacher_db"]):
            return bucket, node_type, node_id, file_path
        raise HTTPException(status_code=403, detail="Snapshot path is outside the authenticated user's workspace")

    if node_type in GLOBAL_READONLY_NODE_TYPES and db_name == "classroomcopilot":
        if write:
            raise HTTPException(status_code=403, detail="Global calendar snapshots are read-only")
        return bucket, node_type, node_id, file_path

    # Institute/curriculum snapshots must be accessed through the caller's institute DB.
    if db_name and db_name in allowed_dbs:
        return bucket, node_type, node_id, file_path

    raise HTTPException(status_code=403, detail="Snapshot path is outside the authenticated user's tenant")


def _storage_for_user(credentials: Dict[str, Any]) -> StorageUser:
    access_token = credentials.get("_access_token")
    if not access_token:
        raise HTTPException(status_code=403, detail="User access token is required for storage access")
    return StorageUser(user_id=credentials.get("sub"), access_token=access_token)


def _is_valid_tldraw_snapshot(snapshot_data: Any) -> bool:
    if not isinstance(snapshot_data, dict):
        return False
    if not ("document" in snapshot_data and "session" in snapshot_data):
        return False
    document = snapshot_data.get("document")
    if isinstance(document, dict) and "schema" in document:
        return True
    return "schemaVersion" in snapshot_data

def create_default_tldraw_content():
    """Create default tldraw content structure."""
    return {
        "document": {
            "store": {
                "document:document": {
                    "gridSize": 10,
                    "name": "",
                    "meta": {},
                    "id": "document:document",
                    "typeName": "document"
                },
                "page:page": {
                    "meta": {},
                    "id": "page:page",
                    "name": "Page 1",
                    "index": "a1",
                    "typeName": "page"
                }
            },
            "schema": {
                "schemaVersion": 2,
                "sequences": {
                    "com.tldraw.store": 4,
                    "com.tldraw.asset": 1,
                    "com.tldraw.camera": 1,
                    "com.tldraw.document": 2,
                    "com.tldraw.instance": 25,
                    "com.tldraw.instance_page_state": 5,
                    "com.tldraw.page": 1,
                    "com.tldraw.instance_presence": 5,
                    "com.tldraw.pointer": 1,
                    "com.tldraw.shape": 4,
                    "com.tldraw.asset.bookmark": 2,
                    "com.tldraw.asset.image": 5,
                    "com.tldraw.asset.video": 5,
                    "com.tldraw.shape.arrow": 5,
                    "com.tldraw.shape.bookmark": 2,
                    "com.tldraw.shape.draw": 2,
                    "com.tldraw.shape.embed": 4,
                    "com.tldraw.shape.frame": 0,
                    "com.tldraw.shape.geo": 9,
                    "com.tldraw.shape.group": 0,
                    "com.tldraw.shape.highlight": 1,
                    "com.tldraw.shape.image": 4,
                    "com.tldraw.shape.line": 5,
                    "com.tldraw.shape.note": 8,
                    "com.tldraw.shape.text": 2,
                    "com.tldraw.shape.video": 2,
                    "com.tldraw.binding.arrow": 0
                }
            },
            "recordVersions": {
                "asset": {"version": 1, "subTypeKey": "type", "subTypeVersions": {}},
                "camera": {"version": 1},
                "document": {"version": 2},
                "instance": {"version": 21},
                "instance_page_state": {"version": 5},
                "page": {"version": 1},
                "shape": {"version": 3, "subTypeKey": "type", "subTypeVersions": {}},
                "instance_presence": {"version": 5},
                "pointer": {"version": 1}
            },
            "rootShapeIds": [],
            "bindings": [],
            "assets": []
        },
        "session": {
            "version": 0,
            "currentPageId": "page:page",
            "pageStates": [{
                "pageId": "page:page",
                "camera": {"x": 0, "y": 0, "z": 1},
                "selectedShapeIds": []
            }]
        }
    }

@router.get("/get_tldraw_node_file")
async def read_tldraw_node_file_from_supabase(
    path: str = Query(..., description="Supabase Storage path (e.g., 'cc.public.snapshots/User/user_id')"),
    db_name: str = Query(..., description="Database name for context"),
    credentials: dict = Depends(SupabaseBearer()),
):
    """
    Load TLDraw snapshot from Supabase Storage.
    
    Args:
        path: Supabase Storage path in format 'bucket/nodetype/node_id'
        db_name: Database name for context (used for logging)
    
    Returns:
        TLDraw snapshot data
    """
    logger.debug(f"Reading tldraw file from Supabase Storage for path: {path}")
    logger.debug(f"Database name: {db_name}")
    
    try:
        bucket, node_type, node_id, file_path = _authorize_snapshot_path(path, db_name, credentials, write=False)
        storage = _storage_for_user(credentials)
        
        logger.debug(f"Bucket: {bucket}")
        logger.debug(f"File path: {file_path}")
        
        try:
            # Try to download the file from Supabase Storage
            file_data = storage.download_file(bucket, file_path)
            
            # Parse JSON data
            try:
                snapshot_data = json.loads(file_data.decode('utf-8'))
            except (UnicodeDecodeError, json.JSONDecodeError) as e:
                logger.warning(f"Malformed TLDraw snapshot {file_path}; returning default content: {e}")
                return create_default_tldraw_content()

            logger.info(f"Successfully loaded tldraw snapshot from Supabase Storage: {file_path}")
            if _is_valid_tldraw_snapshot(snapshot_data):
                return snapshot_data
            logger.warning(f"Snapshot data from {file_path} is missing required TLDraw structure. Using default structure.")
            return create_default_tldraw_content()
                
        except StorageError as e:
            # File doesn't exist, create default content
            logger.info(f"File not found in Supabase Storage, creating default tldraw content: {file_path}")
            
            # Create default tldraw content
            default_content = create_default_tldraw_content()
            
            try:
                # Upload default content to Supabase Storage
                json_data = json.dumps(default_content, indent=2).encode('utf-8')
                storage.upload_file(bucket, file_path, json_data, 'application/json', upsert=True)
                
                logger.info(f"Default tldraw file created in Supabase Storage: {file_path}")
                return default_content
                
            except Exception as upload_error:
                logger.error(f"Error creating default tldraw file in Supabase Storage: {upload_error}")
                raise HTTPException(status_code=500, detail="Error creating default tldraw file")
                
    except HTTPException:
        # Re-raise HTTP exceptions
        raise
    except Exception as e:
        logger.error(f"Unexpected error loading tldraw file from Supabase Storage: {e}")
        raise HTTPException(status_code=500, detail=f"Error loading file: {str(e)}")

@router.post("/set_tldraw_node_file")
async def set_tldraw_node_file_in_supabase(
    path: str = Query(..., description="Supabase Storage path (e.g., 'cc.public.snapshots/User/user_id')"),
    db_name: str = Query(..., description="Database name for context"),
    data: Dict[str, Any] = None,
    credentials: dict = Depends(SupabaseBearer()),
):
    """
    Save TLDraw snapshot to Supabase Storage.
    
    Args:
        path: Supabase Storage path in format 'bucket/nodetype/node_id'
        db_name: Database name for context (used for logging)
        data: TLDraw snapshot data to save
    
    Returns:
        Success status
    """
    logger.debug(f"Saving tldraw file to Supabase Storage for path: {path}")
    logger.debug(f"Database name: {db_name}")
    
    if not data:
        raise HTTPException(status_code=400, detail="Data not provided")
    
    try:
        bucket, node_type, node_id, file_path = _authorize_snapshot_path(path, db_name, credentials, write=True)
        storage = _storage_for_user(credentials)
        
        logger.debug(f"Bucket: {bucket}")
        logger.debug(f"File path: {file_path}")
        
        # Convert data to JSON
        try:
            json_data = json.dumps(data, indent=2).encode('utf-8')
        except (TypeError, ValueError) as e:
            logger.error(f"Failed to serialize data to JSON: {e}")
            raise HTTPException(status_code=400, detail="Invalid data format")
        
        # Upload to Supabase Storage
        try:
            storage.upload_file(bucket, file_path, json_data, 'application/json', upsert=True)
            logger.info(f"Successfully saved tldraw snapshot to Supabase Storage: {file_path}")
            return {"status": "success", "message": "File saved successfully"}
            
        except Exception as upload_error:
            logger.error(f"Error uploading file to Supabase Storage: {upload_error}")
            raise HTTPException(status_code=500, detail="Error saving file")
            
    except HTTPException:
        # Re-raise HTTP exceptions
        raise
    except Exception as e:
        logger.error(f"Unexpected error saving tldraw file to Supabase Storage: {e}")
        raise HTTPException(status_code=500, detail=f"Error saving file: {str(e)}")
