import os
import uuid
import shutil
from pathlib import Path
from typing import List, Dict, Any, Optional
from fastapi import APIRouter, HTTPException, File, UploadFile
from pydantic import BaseModel
from utils.asset_directory_utils import get_app_data_directory_env
import uuid

try:
    from fontTools.ttLib import TTFont
    from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e
    FONTTOOLS_AVAILABLE = True
except ImportError:
    FONTTOOLS_AVAILABLE = False

FONTS_ROUTER = APIRouter(prefix="/fonts", tags=["fonts"])

# Supported font file extensions
SUPPORTED_FONT_EXTENSIONS = {
    '.ttf': 'font/ttf',
    '.otf': 'font/otf', 
    '.woff': 'font/woff',
    '.woff2': 'font/woff2',
    '.eot': 'application/vnd.ms-fontobject'
}

class FontUploadResponse(BaseModel):
    success: bool
    font_name: str
    font_url: str
    font_path: str
    message: Optional[str] = None

class FontListResponse(BaseModel):
    success: bool
    fonts: List[dict]
    message: Optional[str] = None


def get_fonts_directory() -> str:
    """Get the fonts directory path, create if it doesn't exist"""
    app_data_dir = get_app_data_directory_env() or "/tmp/deckforge"
    fonts_dir = os.path.join(app_data_dir, "fonts")
    os.makedirs(fonts_dir, exist_ok=True)
    return fonts_dir


def is_valid_font_file(file: UploadFile) -> bool:
    """Validate font file by extension and MIME type"""
    if not file.filename:
        return False
    
    file_ext = os.path.splitext(file.filename)[1].lower()
    if file_ext not in SUPPORTED_FONT_EXTENSIONS:
        return False
    
    # Check MIME type
    content_type = file.content_type or ""
    valid_mime_types = [
        "font/ttf", "font/otf", "font/woff", "font/woff2",
        "application/font-ttf", "application/font-otf", 
        "application/font-woff", "application/font-woff2",
        "application/x-font-ttf", "application/x-font-otf",
        "font/truetype", "font/opentype"
    ]
    
    return content_type in valid_mime_types


def extract_font_name_from_file(file_path: str) -> str:
    """Extract the actual font family name from font file metadata"""
    if not FONTTOOLS_AVAILABLE:
        # Fallback to filename parsing if fonttools not available
        filename = os.path.basename(file_path)
        base_name = os.path.splitext(filename)[0]
        if '_' in filename and len(filename.split('_')[-1].split('.')[0]) == 8:
            # Remove UUID part
            parts = filename.split('_')
            if len(parts) > 1:
                return '_'.join(parts[:-1])
        return base_name
    
    try:
        font = TTFont(file_path)
        
        # Try to get font family name from name table
        if 'name' in font:
            name_table = font['name']
            
            # Preferred order: Family name (ID 1), then Full name (ID 4), then PostScript name (ID 6)
            for name_id in [1, 4, 6]:
                for record in name_table.names:
                    if record.nameID == name_id:
                        # Prefer English names
                        if record.langID == 0x409 or record.langID == 0:  # English
                            font_name = record.toUnicode().strip()
                            if font_name:
                                font.close()
                                return font_name
            
            # If no English name found, use any available family name
            for record in name_table.names:
                if record.nameID == 1:  # Family name
                    font_name = record.toUnicode().strip()
                    if font_name:
                        font.close()
                        return font_name
        
        font.close()
    except Exception as e:
        # If font parsing fails, fallback to filename
        print(f"Error reading font metadata from {file_path}: {e}")
    
    # Fallback to filename parsing
    filename = os.path.basename(file_path)
    base_name = os.path.splitext(filename)[0]
    if '_' in filename and len(filename.split('_')[-1].split('.')[0]) == 8:
        # Remove UUID part
        parts = filename.split('_')
        if len(parts) > 1:
            return '_'.join(parts[:-1])
    return base_name


@FONTS_ROUTER.post("/upload", response_model=FontUploadResponse)
async def upload_font(
    font_file: UploadFile = File(..., description="Font file to upload (.ttf, .otf, .woff, .woff2, .eot)")
):
    """
    Upload a font file and save it to the fonts directory.
    
    Args:
        font_file: Uploaded font file
    
    Returns:
        FontUploadResponse with font details and accessible URL
    
    Raises:
        HTTPException: If file validation fails or upload error occurs
    """
    try:
        # Validate file
        if not font_file.filename:
            raise HTTPException(
                status_code=400,
                detail="No file name provided"
            )
        
        if not is_valid_font_file(font_file):
            raise HTTPException(
                status_code=400,
                detail=f"Invalid font file. Supported formats: {', '.join(SUPPORTED_FONT_EXTENSIONS.keys())}"
            )
        
        # Generate unique filename to avoid conflicts
        file_ext = os.path.splitext(font_file.filename)[1].lower()
        base_name = os.path.splitext(font_file.filename)[0]
        unique_filename = f"{base_name}_{str(uuid.uuid4())[:8]}{file_ext}"
        
        # Get fonts directory
        fonts_dir = get_fonts_directory()
        font_path = os.path.join(fonts_dir, unique_filename)
        
        # Save the uploaded file
        with open(font_path, "wb") as buffer:
            shutil.copyfileobj(font_file.file, buffer)
        
        # Generate accessible URL
        font_url = f"/app_data/fonts/{unique_filename}"
        
        return FontUploadResponse(
            success=True,
            font_name=base_name,
            font_url=font_url,
            font_path=font_path,
            message=f"Font '{base_name}' uploaded successfully"
        )
        
    except HTTPException:
        # Re-raise HTTP exceptions as-is
        raise
    except Exception as e:
        print(f"Error uploading font: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Error uploading font: {str(e)}"
        )


@FONTS_ROUTER.get("/list", response_model=FontListResponse)
async def list_fonts():
    """
    List all uploaded fonts with their accessible URLs.
    
    Returns:
        FontListResponse with list of available fonts
    """
    try:
        fonts_dir = get_fonts_directory()
        fonts = []
        
        # Get all font files in the directory
        if os.path.exists(fonts_dir):
            for filename in os.listdir(fonts_dir):
                file_path = os.path.join(fonts_dir, filename)
                
                if os.path.isfile(file_path):
                    file_ext = os.path.splitext(filename)[1].lower()
                    
                    if file_ext in SUPPORTED_FONT_EXTENSIONS:
                        # Get the real font name from file metadata
                        font_name = extract_font_name_from_file(file_path)
                        
                        # Extract original name (remove UUID suffix for display)
                        base_name = filename
                        if '_' in filename and len(filename.split('_')[-1].split('.')[0]) == 8:
                            # Remove UUID part for original_name display
                            parts = filename.split('_')
                            if len(parts) > 1:
                                base_name = '_'.join(parts[:-1]) + file_ext
                        
                        fonts.append({
                            "filename": filename,
                            "font_name": font_name,  # Real font family name from metadata
                            "original_name": base_name,
                            "font_url": f"/app_data/fonts/{filename}",
                            "font_type": SUPPORTED_FONT_EXTENSIONS.get(file_ext, 'unknown'),
                            "file_size": os.path.getsize(file_path)
                        })
        
        return FontListResponse(
            success=True,
            fonts=fonts,
            message=f"Found {len(fonts)} font files"
        )
        
    except Exception as e:
        print(f"Error listing fonts: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Error listing fonts: {str(e)}"
        )


@FONTS_ROUTER.delete("/delete/{filename}")
async def delete_font(filename: str):
    """
    Delete a font file from the fonts directory.
    
    Args:
        filename: Name of the font file to delete
    
    Returns:
        Success message
    """
    try:
        fonts_dir = get_fonts_directory()
        font_path = os.path.join(fonts_dir, filename)
        
        if not os.path.exists(font_path):
            raise HTTPException(
                status_code=404,
                detail=f"Font file '{filename}' not found"
            )
        
        # Validate it's actually a font file before deleting
        file_ext = os.path.splitext(filename.lower())[1]
        if file_ext not in SUPPORTED_FONT_EXTENSIONS:
            raise HTTPException(
                status_code=400,
                detail="File is not a recognized font format"
            )
        
        os.remove(font_path)
        
        return {
            "success": True,
            "message": f"Font '{filename}' deleted successfully"
        }
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"Error deleting font: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Error deleting font: {str(e)}"
        ) 